150 Commits

Author SHA1 Message Date
Uwe L. Korn
17c897976c Do not assume dss never decreases.
An sbrk() caller outside jemalloc can decrease the dss, so add a
separate atomic boolean to explicitly track whether jemalloc is
concurrently calling sbrk(), rather than depending on state outside
jemalloc's full control.

Fixes #802 for stable-4
2017-09-11 11:01:21 -07:00
Jim Chen
7883c7749f Use openat syscall if available
Some architectures like AArch64 may not have the open syscall because it
was superseded by the openat syscall, so check and use SYS_openat if
SYS_open is not available.

Additionally, Android headers for AArch64 define SYS_open to __NR_open,
even though __NR_open is undefined. Undefine SYS_open in that case so
SYS_openat is used.
2017-05-12 10:34:32 -07:00
Jason Evans
807a9a3e17 Fix decommit-related run fragmentation.
When allocating runs with alignment stricter than one page, commit after
trimming the head/tail from the initial over-sized allocation, rather
than before trimming.  This avoids creating clean-but-committed runs;
such runs do not get purged (and decommitted as a side effect), so they
can cause unnecessary long-term run fragmentation.

Do not commit decommitted memory in chunk_recycle() unless asked to by
the caller.  This allows recycled arena chunks to start in the
decommitted state, and therefore increases the likelihood that purging
after run deallocation will allow the arena chunk to become a single
unused run, thus allowing the chunk as a whole to be discarded.

This resolves #766.
2017-04-18 12:08:28 -07:00
Jason Evans
04380e79f1 Merge branch 'rc-4.5.0' 2017-02-28 19:09:23 -08:00
Jason Evans
700253e1f2 Update ChangeLog for 4.5.0. 2017-02-28 16:21:05 -08:00
Jason Evans
2406c22f36 Add casts to CONF_HANDLE_T_U().
This avoids signed/unsigned comparison warnings when specifying integer
constants as inputs.

Clean up whitespace and add clarifying parentheses for
CONF_HANDLE_SIZE_T(opt_lg_chunk, ...).
2017-02-28 16:20:44 -08:00
Jason Evans
e723f99dec Alphabetize private symbol names. 2017-02-28 15:06:27 -08:00
Jason Evans
d84d2909c3 Fix/enhance THP integration.
Detect whether chunks start off as THP-capable by default (according to
the state of /sys/kernel/mm/transparent_hugepage/enabled), and use this
as the basis for whether to call pages_nohuge() once per chunk during
first purge of any of the chunk's page runs.

Add the --disable-thp configure option, as well as the the opt.thp
mallctl.

This resolves #541.
2017-02-28 14:25:06 -08:00
Jason Evans
766ddcd0f2 restructure *CFLAGS configuration.
Convert CFLAGS to be a concatenation:

  CFLAGS := CONFIGURE_CFLAGS SPECIFIED_CFLAGS EXTRA_CFLAGS

This ordering makes it possible to override the flags set by the
configure script both during and after configuration, with CFLAGS and
EXTRA_CFLAGS, respectively.

This resolves #619.
2017-02-28 12:54:40 -08:00
Qi Wang
7b53fe928e Handle race in stats_arena_bins_print
When multiple threads calling stats_print, race could happen as we read the
counters in separate mallctl calls; and the removed assertion could fail when
other operations happened in between the mallctl calls. For simplicity, output
"race" in the utilization field in this case.

This resolves #616.
2017-02-27 15:25:38 -08:00
Jason Evans
7c124830a1 Fix lg_chunk clamping for config_cache_oblivious.
Fix lg_chunk clamping to take into account cache-oblivious large
allocation.  This regression only resulted in incorrect behavior if
!config_fill (false unless --disable-fill specified) and
config_cache_oblivious (true unless --disable-cache-oblivious
specified).

This regression was introduced by
8a03cf039c (Implement cache index
randomization for large allocations.), which was first released in
4.0.0.

This resolves #555.
2017-02-27 15:19:41 -08:00
Jason Evans
1027a2682b Add some missing explicit casts.
This resolves #614.
2017-02-27 14:41:01 -08:00
Jason Evans
1e2c9ef8d6 Fix huge-aligned allocation.
This regression was caused by
b9408d77a6 (Fix/simplify chunk_recycle()
allocation size computations.).

This resolves #647.
2017-02-27 11:08:19 -08:00
Jason Evans
ed19a48928 Silence harmless warnings discovered via run_tests.sh. 2017-02-26 11:04:58 -08:00
Jason Evans
54d2d697b2 Test JSON output of malloc_stats_print() and fix bugs.
Implement and test a JSON validation parser.  Use the parser to validate
JSON output from malloc_stats_print(), with a significant subset of
supported output options.

This resolves #583.
2017-02-26 11:04:58 -08:00
Jason Evans
61d26425e5 Fix JSON-mode output for !config_stats and/or !config_prof cases.
These bugs were introduced by b599b32280
(Add "J" (JSON) support to malloc_stats_print().), which was first
released in 4.3.0.

This resolves #615.
2017-02-26 11:04:58 -08:00
Jason Evans
adae7cfc4a Fix chunk_alloc_dss() regression.
Fix chunk_alloc_dss() to account for bytes that are not a multiple of
the chunk size.  This regression was introduced by
e2bcf037d4 (Make dss operations
lockless.), which was first released in 4.3.0.
2017-02-26 10:53:26 -08:00
Jason Evans
08c24e7c1a Relax witness assertions related to prof_gdump().
In some cases the prof machinery allocates (in order to modify the
bt2gctx hash table), and such operations are synchronized via
bt2gctx_mtx.  Rather than asserting that no locks are held on entry
into functions that may call prof_gdump(), make the weaker assertion
that no "core" locks are held.  The prof machinery enqueues dumps
triggered by prof_gdump() calls when bt2gctx_mtx is held, so this
weakened assertion avoids false failures in such cases.
2017-02-23 10:08:42 -08:00
Jason Evans
f56cb9a68e Add witness_assert_depth[_to_rank]().
This makes it possible to make lock state assertions about precisely
which locks are held.
2017-02-23 10:08:42 -08:00
Jason Evans
7034e6baa1 Enable mutex witnesses even when !isthreaded.
This fixes interactions with witness_assert_depth[_to_rank](), which was
added in dad74bd3c8 (Convert
witness_assert_lockless() to witness_assert_lock_depth().).
2017-02-23 10:08:42 -08:00
David Goldblatt
44e50041dc CI: Run --enable-debug builds on windows
This will hopefully catch some windows-specific bugs.
2017-02-23 10:06:15 -08:00
Jason Evans
e85e588e45 Use MALLOC_CONF rather than malloc_conf for tests.
malloc_conf does not reliably work with MSVC, which complains of
"inconsistent dll linkage", i.e. its inability to support the
application overriding malloc_conf when dynamically linking/loading.
Work around this limitation by adding test harness support for per test
shell script sourcing, and converting all tests to use MALLOC_CONF
instead of malloc_conf.
2017-02-23 10:06:15 -08:00
Jason Evans
3ecc3c8486 Fix/refactor tcaches synchronization.
Synchronize tcaches with tcaches_mtx rather than ctl_mtx.  Add missing
synchronization for tcache flushing.  This bug was introduced by
1cb181ed63 (Implement explicit tcache
support.), which was first released in 4.0.0.
2017-02-23 10:06:15 -08:00
Jason Evans
fdba5ad5cc Repair file permissions.
This regression was caused by 8f61fdedb9
(Uniformly cast mallctl[bymib]() oldp/newp arguments to (void *).).

This resolves #538.
2017-02-22 00:24:32 -08:00
David Goldblatt
d4f3f9a03f Beef up travis CI integration testing
Introduces gen_travis.py, which generates .travis.yml, and updates .travis.yml
to be the generated version.

The travis build matrix approach doesn't play well with mixing and matching
various different environment settings, so we generate every build explicitly,
rather than letting them do it for us.

To avoid abusing travis resources (and save us time waiting for CI results), we
don't test every possible combination of options; we only check up to 2 unusual
settings at a time.
2017-02-21 12:45:59 -08:00
Tamir Duberstein
b973ec7975 Avoid redeclaring glibc's secure_getenv
Avoid the name secure_getenv to avoid redeclaring secure_getenv when
secure_getenv is present but its use is manually disabled via
ac_cv_func_secure_getenv=no.
2017-01-25 11:22:28 -08:00
Jason Evans
b49c649bc1 Fix lock order reversal during gdump. 2017-01-24 12:50:06 -08:00
Jason Evans
dad74bd3c8 Convert witness_assert_lockless() to witness_assert_lock_depth().
This makes it possible to make lock state assertions about precisely
which locks are held.
2017-01-24 12:50:06 -08:00
Mike Hommey
c6943acb3c Add dummy implementations for most remaining OSX zone allocator functions
Some system libraries are using malloc_default_zone() and then using
some of the malloc_zone_* API. Under normal conditions, those functions
check the malloc_zone_t/malloc_introspection_t struct for the values
that are allowed to be NULL, so that a NULL deref doesn't happen.

As of OSX 10.12, malloc_default_zone() doesn't return the actual default
zone anymore, but returns a fake, wrapper zone. The wrapper zone defines
all the possible functions in the malloc_zone_t/malloc_introspection_t
struct (almost), and calls the function from the registered default zone
(jemalloc in our case) on its own. Without checking whether the pointers
are NULL.

This means that a system library that calls e.g.
malloc_zone_batch_malloc(malloc_default_zone(), ...) ends up trying to
call jemalloc_zone.batch_malloc, which is NULL, and crash follows.

So as of OSX 10.12, the default zone is required to have all the
functions available (really, the same as the wrapper zone), even if they
do nothing.

This is arguably a bug in libsystem_malloc in OSX 10.12, but jemalloc
still needs to work in that case.
2017-01-17 20:12:24 -08:00
Mike Hommey
c68bb41793 Don't rely on OSX SDK malloc/malloc.h for malloc_zone struct definitions
The SDK jemalloc is built against might be not be the latest for various
reasons, but the resulting binary ought to work on newer versions of
OSX.

In order to ensure this, we need the fullest definitions possible, so
copy what we need from the latest version of malloc/malloc.h available
on opensource.apple.com.
2017-01-17 20:12:24 -08:00
John Paul Adrian Glaubitz
9389335b86 Use better pre-processor defines for sparc64
Currently, jemalloc detects sparc64 targets by checking whether
__sparc64__ is defined. However, this definition is used on BSD
targets only. Linux targets define both __sparc__ and __arch64__
for sparc64. Since this also works on BSD, rather use __sparc__
and __arch64__ instead of __sparc64__ to detect sparc64 targets.
2017-01-13 09:01:33 -08:00
Jason Evans
f1f7635731 Merge branch 'rc-4.4.0' 2016-12-03 22:48:43 -08:00
Jason Evans
2d1bb8980f Update ChangeLog for 4.4.0. 2016-12-03 22:44:24 -08:00
Jason Evans
145f3cd173 Add --disable-syscall.
This resolves #517.
2016-12-03 16:56:19 -08:00
Jason Evans
e1b2970d28 Update configure cache file example. 2016-12-03 16:09:25 -08:00
Jason Evans
34a7e37a71 Fix pages_purge() when using MADV_DONTNEED.
This fixes a regression caused by
e98a620c59 (Mark partially purged arena
chunks as non-hugepage.).
2016-12-03 16:06:19 -08:00
John Szakmeister
a05d4da4d8 Implement a more reliable detection scheme for os_unfair_lock.
The core issue here is the weak linking of the symbol, and in certain
environments--for instance, using the latest Xcode (8.1) with the latest
SDK (10.12)--os_unfair_lock may resolve even though you're compiling on
a host that doesn't support it (10.11).

We can use the availability macros to circumvent this problem, and
detect that we're not compiling for a target that is going to support
them and error out at compile time.  The other alternative is to do a
runtime check, but that presents issues for cross-compiling.
2016-11-28 17:44:29 -08:00
Jason Evans
e98a620c59 Mark partially purged arena chunks as non-hugepage.
Add the pages_[no]huge() functions, which toggle huge page state via
madvise(..., MADV_[NO]HUGEPAGE) calls.

The first time a page run is purged from within an arena chunk, call
pages_nohuge() to tell the kernel to make no further attempts to back
the chunk with huge pages.  Upon arena chunk deletion, restore the
associated virtual memory to its original state via pages_huge().

This resolves #243.
2016-11-24 00:15:55 -08:00
Jason Evans
fc11f3cb84 Enable overriding JEMALLOC_{ALLOC,FREE}_JUNK.
This resolves #509.
2016-11-22 11:02:28 -08:00
Jason Evans
949a27fc32 Add pthread_atfork(3) feature test.
Some versions of Android provide a pthreads library without providing
pthread_atfork(), so in practice a separate feature test is necessary
for the latter.
2016-11-17 15:16:27 -08:00
Jason Evans
62f2d84e7a Refactor madvise(2) configuration.
Add feature tests for the MADV_FREE and MADV_DONTNEED flags to
madvise(2), so that MADV_FREE is detected and used for Linux kernel
versions 4.5 and newer.  Refactor pages_purge() so that on systems which
support both flags, MADV_FREE is preferred over MADV_DONTNEED.

This resolves #387.
2016-11-17 10:37:48 -08:00
Jason Evans
e7ca53bac2 Remove a residual comment. 2016-11-16 19:42:03 -08:00
Jason Evans
0d6a472db9 Avoid gcc tautological-compare warnings. 2016-11-16 18:53:59 -08:00
Jason Evans
3ea838d2a2 Avoid gcc type-limits warnings. 2016-11-16 18:32:24 -08:00
Jason Evans
8e3fb7f417 Document how to use --cache configure option.
This resolves #494.
2016-11-16 10:58:32 -08:00
Jason Evans
2a24dc2476 Revert "Add JE_RUNNABLE() and use it for os_unfair_lock_*() test."
This reverts commit 45f83a2ac6.

JE_RUNNABLE() causes general cross-compilation issues.
2016-11-16 10:40:48 -08:00
Jason Evans
6468dd52f3 Fix an MSVC compiler warning. 2016-11-15 21:08:28 -08:00
Jason Evans
8f61fdedb9 Uniformly cast mallctl[bymib]() oldp/newp arguments to (void *).
This avoids warnings in some cases, and is otherwise generally good
hygiene.
2016-11-15 15:00:28 -08:00
Jason Evans
84ae603577 Explicitly cast negative constants meant for use as unsigned. 2016-11-15 14:05:16 -08:00
Jason Evans
72c587a411 Add cast to silence (harmless) conversion warning. 2016-11-15 14:05:00 -08:00
Jason Evans
87004d238c Avoid negation of unsigned numbers.
Rather than relying on two's complement negation for alignment mask
generation, use bitwise not and addition.  This dodges warnings from
MSVC, and should be strength-reduced by compiler optimization anyway.
2016-11-15 14:04:35 -08:00
Jason Evans
2379479225 Consistently use size_t rather than uint64_t for extent serial numbers. 2016-11-15 13:47:22 -08:00
Jason Evans
6a71d37a75 Add packing test, which verifies stable layout policy. 2016-11-15 13:33:47 -08:00
Jason Evans
5c77af98b1 Add extent serial numbers.
Add extent serial numbers and use them where appropriate as a sort key
that is higher priority than address, so that the allocation policy
prefers older extents.

This resolves #147.
2016-11-15 13:33:40 -08:00
Jason Evans
45f83a2ac6 Add JE_RUNNABLE() and use it for os_unfair_lock_*() test.
This resolves #494.
2016-11-12 09:47:07 -08:00
Jason Evans
ded4f38ffd Reduce memory usage for sdallocx() test_alignment_and_size. 2016-11-11 23:49:40 -08:00
Jason Evans
1aeea0f391 Simplify extent_quantize().
2cdf07aba9 (Fix extent_quantize() to
handle greater-than-huge-size extents.) solved a non-problem; the
expression passed in to index2size() was never too large.  However the
expression could in principle underflow, so fix the actual (latent) bug
and remove unnecessary complexity.
2016-11-11 22:46:55 -08:00
Jason Evans
a2af09f025 Remove overly restrictive stats_cactive_{add,sub}() assertions.
This fixes a regression caused by
40ee9aa957 (Fix stats.cactive accounting
regression.) and first released in 4.1.0.
2016-11-11 22:19:10 -08:00
Jason Evans
b9408d77a6 Fix/simplify chunk_recycle() allocation size computations.
Remove outer CHUNK_CEILING(s2u(...)) from alloc_size computation, since
s2u() may overflow (and return 0), and CHUNK_CEILING() is only needed
around the alignment portion of the computation.

This fixes a regression caused by
5707d6f952 (Quantize szad trees by size
class.) and first released in 4.0.0.

This resolves #497.
2016-11-11 22:18:39 -08:00
Jason Evans
2cdf07aba9 Fix extent_quantize() to handle greater-than-huge-size extents.
Allocation requests can't directly create extents that exceed
HUGE_MAXCLASS, but extent merging can create them.

This fixes a regression caused by
8a03cf039c (Implement cache index
randomization for large allocations.) and first released in 4.0.0.

This resolves #497.
2016-11-11 22:17:27 -08:00
Jason Evans
e916d55ba1 Add configure support for *-*-linux-android.
This is tailored to Android, i.e. more specific than the *-*-linux*
configuration.

This resolves #471.
2016-11-10 15:40:23 -08:00
Samuel Moritz
092d760817 Support Debian GNU/kFreeBSD.
Treat it exactly like Linux since they both use GNU libc.
2016-11-10 15:39:33 -08:00
Jason Evans
b4486dce24 Update config.{guess,sub} from upstream. 2016-11-10 15:08:32 -08:00
Jason Evans
0110fa8451 Merge branch 'rc-4.3.1' 2016-11-07 17:21:12 -08:00
Jason Evans
b0f56583b7 Update ChangeLog for 4.3.1. 2016-11-07 16:22:25 -08:00
Jason Evans
7b8e74f48f Revert "Define 64-bits atomics unconditionally"
This reverts commit af33e9a597.

This resolves #495.
2016-11-07 11:51:05 -08:00
Jason Evans
5d6cb6eb66 Refactor prng to not use 64-bit atomics on 32-bit platforms.
This resolves #495.
2016-11-07 11:50:59 -08:00
Jason Evans
a4e83e8593 Fix run leak.
Fix arena_run_first_best_fit() to search all potentially non-empty
runs_avail heaps, rather than ignoring the heap that contains runs
larger than large_maxclass, but less than chunksize.

This fixes a regression caused by
f193fd80cf (Refactor runs_avail.).

This resolves #493.
2016-11-07 09:43:39 -08:00
Jason Evans
9bef119b42 Merge branch 'rel-4.3.0' 2016-11-04 17:46:17 -07:00
Jason Evans
8019f4c21c Merge branch 'rel-4.3.0' 2016-11-04 17:38:52 -07:00
Jason Evans
23f04ef9b7 Update ChangeLog for 4.3.0. 2016-11-04 15:15:40 -07:00
Jason Evans
28b7e42e44 Fix arena data structure size calculation.
Fix paren placement so that QUANTUM_CEILING() applies to the correct
portion of the expression that computes how much memory to base_alloc().
In practice this bug had no impact.  This was caused by
5d8db15db9 (Simplify run quantization.),
which in turn fixed an over-allocation regression caused by
3c4d92e82a (Add per size class huge
allocation statistics.).
2016-11-04 15:00:08 -07:00
Matthew Parkinson
77635bf532 Fixes to Visual Studio Project files 2016-11-04 10:01:31 -07:00
Jason Evans
cb3ad659f0 Use -std=gnu11 if available.
This supersedes -std=gnu99, and enables C11 atomics.
2016-11-04 01:11:48 -07:00
Jason Evans
213667fe26 Update ChangeLog for 4.3.0. 2016-11-04 00:04:27 -07:00
Jason Evans
32896a902b Fix large allocation to search optimal size class heap.
Fix arena_run_alloc_large_helper() to not convert size to usize when
searching for the first best fit via arena_run_first_best_fit().  This
allows the search to consider the optimal quantized size class, so that
e.g. allocating and deallocating 40 KiB in a tight loop can reuse the
same memory.

This regression was nominally caused by
5707d6f952 (Quantize szad trees by size
class.), but it did not commonly cause problems until
8a03cf039c (Implement cache index
randomization for large allocations.).  These regressions were first
released in 4.0.0.

This resolves #487.
2016-11-03 22:36:30 -07:00
Jason Evans
e9012630ac Fix chunk_alloc_cache() to support decommitted allocation.
Fix chunk_alloc_cache() to support decommitted allocation, and use this
ability in arena_chunk_alloc_internal() and arena_stash_dirty(), so that
chunks don't get permanently stuck in a hybrid state.

This resolves #487.
2016-11-03 22:36:30 -07:00
Jason Evans
dd3ed23aea Update symbol mangling. 2016-11-03 14:55:58 -07:00
Jason Evans
1ceae2f8cb Update ChangeLog for 4.3.0. 2016-11-02 21:42:16 -07:00
Jason Evans
62de7680ca Update project URL. 2016-11-02 21:42:16 -07:00
Dave Watson
6c56e194b0 Check for existance of CPU_COUNT macro before using it.
This resolves #485.
2016-11-02 19:54:19 -07:00
Jason Evans
eca3bc0131 Fix sycall(2) configure test for Linux. 2016-11-02 19:51:23 -07:00
Jason Evans
da206df10b Do not use syscall(2) on OS X 10.12 (deprecated). 2016-11-02 19:35:12 -07:00
Jason Evans
3f2b8d9cfa Add os_unfair_lock support.
OS X 10.12 deprecated OSSpinLock; os_unfair_lock is the recommended
replacement.
2016-11-02 19:35:12 -07:00
Jason Evans
a99e0fa2d2 Fix/refactor zone allocator integration code.
Fix zone_force_unlock() to reinitialize, rather than unlocking mutexes,
since OS X 10.12 cannot tolerate a child unlocking mutexes that were
locked by its parent.

Refactor; this was a side effect of experimenting with zone
{de,re}registration during fork(2).
2016-11-02 19:35:09 -07:00
Jason Evans
31db315f17 Call _exit(2) rather than exit(3) in forked child.
_exit(2) is async-signal-safe, whereas exit(3) is not.
2016-11-02 19:24:49 -07:00
Jason Evans
07ee4c5ff4 Force no lazy-lock on Windows.
Monitoring thread creation is unimplemented for Windows, which means
lazy-lock cannot function correctly.

This resolves #310.
2016-11-02 09:13:08 -07:00
Jason Evans
f19bedb04c Use <quote>...</quote> rather than &ldquo;...&rdquo; or "..." in XML. 2016-11-01 15:32:40 -07:00
Jason Evans
b599b32280 Add "J" (JSON) support to malloc_stats_print().
This resolves #474.
2016-11-01 15:32:37 -07:00
Jason Evans
4752a54eeb Refactor witness_unlock() to fix undefined test behavior.
This resolves #396.
2016-10-31 11:51:39 -07:00
Jason Evans
1d57c03e33 Use CLOCK_MONOTONIC_COARSE rather than COARSE_MONOTONIC_RAW.
The raw clock variant is slow (even relative to plain CLOCK_MONOTONIC),
whereas the coarse clock variant is faster than CLOCK_MONOTONIC, but
still has resolution (~1ms) that is adequate for our purposes.

This resolves #479.
2016-10-29 22:59:42 -07:00
Jason Evans
c443b67561 Use syscall(2) rather than {open,read,close}(2) during boot.
Some applications wrap various system calls, and if they call the
allocator in their wrappers, unexpected reentry can result.  This is not
a general solution (many other syscalls are spread throughout the code),
but this resolves a bootstrapping issue that is apparently common.

This resolves #443.
2016-10-29 22:46:52 -07:00
Jason Evans
35a108c809 Fix EXTRA_CFLAGS to not affect configuration. 2016-10-29 22:46:43 -07:00
Jason Evans
e46f8f97bc Do not mark malloc_conf as weak on Windows.
This works around malloc_conf not being properly initialized by at least
the cygwin toolchain.  Prior build system changes to use
-Wl,--[no-]whole-archive may be necessary for malloc_conf resolution to
work properly as a non-weak symbol (not tested).
2016-10-29 00:16:30 -07:00
Jason Evans
35799a5030 Do not mark malloc_conf as weak for unit tests.
This is generally correct (no need for weak symbols since no jemalloc
library is involved in the link phase), and avoids linking problems
(apparently unininitialized non-NULL malloc_conf) when using cygwin with
gcc.
2016-10-28 23:21:14 -07:00
Dave Watson
ed84764a2a Support static linking of jemalloc with glibc
glibc defines its malloc implementation with several weak and strong
symbols:

strong_alias (__libc_calloc, __calloc) weak_alias (__libc_calloc, calloc)
strong_alias (__libc_free, __cfree) weak_alias (__libc_free, cfree)
strong_alias (__libc_free, __free) strong_alias (__libc_free, free)
strong_alias (__libc_malloc, __malloc) strong_alias (__libc_malloc, malloc)

The issue is not with the weak symbols, but that other parts of glibc
depend on __libc_malloc explicitly.  Defining them in terms of jemalloc
API's allows the linker to drop glibc's malloc.o completely from the link,
and static linking no longer results in symbol collisions.

Another wrinkle: jemalloc during initialization calls sysconf to
get the number of CPU's.  GLIBC allocates for the first time before
setting up isspace (and other related) tables, which are used by
sysconf.  Instead, use the pthread API to get the number of
CPUs with GLIBC, which seems to work.

This resolves #442.
2016-10-28 15:10:19 -07:00
Jason Evans
b99c72f3d2 Reduce memory requirements for regression tests.
This is intended to drop memory usage to a level that AppVeyor test
instances can handle.

This resolves #393.
2016-10-28 11:56:16 -07:00
Jason Evans
eaecaad8ea Periodically purge in memory-intensive integration tests.
This resolves #393.
2016-10-28 11:55:09 -07:00
Jason Evans
2c53faf352 Periodically purge in memory-intensive integration tests.
This resolves #393.
2016-10-28 11:54:56 -07:00
Jason Evans
e7d6779918 Only link with libm (-lm) if necessary.
This fixes warnings when building with MSVC.
2016-10-28 00:48:03 -07:00
Jason Evans
875ff15e6a Only use --whole-archive with gcc.
Conditionalize use of --whole-archive on the platform plus compiler,
rather than on the ABI.  This fixes a regression caused by
7b24c6e557 (Use --whole-archive when
linking integration tests on MinGW.).
2016-10-28 00:47:53 -07:00
Jason Evans
1eb801bcad Do not force lazy lock on Windows.
This reverts 13473c7c66, which was
intended to work around bootstrapping issues when linking statically.
However, this actually causes problems in various other configurations,
so this reversion may force a future fix for the underlying problem, if
it still exists.
2016-10-28 00:47:42 -07:00
Jason Evans
dc553d52d8 Fix over-sized allocation of rtree leaf nodes.
Use the correct level metadata when allocating child nodes so that leaf
nodes don't end up over-sized (2^16 elements vs 2^4 elements).
2016-10-28 00:41:15 -07:00
Jason Evans
5569b4a42c Use --whole-archive when linking integration tests on MinGW.
Prior to this change, the malloc_conf weak symbol provided by the
jemalloc dynamic library is always used, even if the application
provides a malloc_conf symbol.  Use the --whole-archive linker option
to allow the weak symbol to be overridden.
2016-10-25 21:52:36 -07:00
Jason Evans
962a2979e3 Do not (recursively) allocate within tsd_fetch().
Refactor tsd so that tsdn_fetch() does not trigger allocation, since
allocation could cause infinite recursion.

This resolves #458.
2016-10-21 00:27:37 -07:00
Jason Evans
e2bcf037d4 Make dss operations lockless.
Rather than protecting dss operations with a mutex, use atomic
operations.  This has negligible impact on synchronization overhead
during typical dss allocation, but is a substantial improvement for
chunk_in_dss() and the newly added chunk_dss_mergeable(), which can be
called multiple times during chunk deallocations.

This change also has the advantage of avoiding tsd in deallocation paths
associated with purging, which resolves potential deadlocks during
thread exit due to attempted tsd resurrection.

This resolves #425.
2016-10-13 15:33:56 -07:00
Jason Evans
9737685943 Add/use adaptive spinning.
Add spin_t and spin_{init,adaptive}(), which provide a simple
abstraction for adaptive spinning.

Adaptively spin during busy waits in bootstrapping and rtree node
initialization.
2016-10-13 14:58:38 -07:00
Jason Evans
a2539fab95 Disallow 0x5a junk filling when running in Valgrind.
Explicitly disallow junk:true and junk:free runtime settings when
running in Valgrind, since deallocation-time junk filling and redzone
validation cause false positive Valgrind reports.

This resolves #470.
2016-10-12 22:58:40 -07:00
Jason Evans
d419bb09ef Fix and simplify decay-based purging.
Simplify decay-based purging attempts to only be triggered when the
epoch is advanced, rather than every time purgeable memory increases.
In a correctly functioning system (not previously the case; see below),
this only causes a behavior difference if during subsequent purge
attempts the least recently used (LRU) purgeable memory extent is
initially too large to be purged, but that memory is reused between
attempts and one or more of the next LRU purgeable memory extents are
small enough to be purged.  In practice this is an arbitrary behavior
change that is within the set of acceptable behaviors.

As for the purging fix, assure that arena->decay.ndirty is recorded
*after* the epoch advance and associated purging occurs.  Prior to this
fix, it was possible for purging during epoch advance to cause a
substantially underrepresentative (arena->ndirty - arena->decay.ndirty),
i.e. the number of dirty pages attributed to the current epoch was too
low, and a series of unintended purges could result.  This fix is also
relevant in the context of the simplification described above, but the
bug's impact would be limited to over-purging at epoch advances.
2016-10-11 15:50:05 -07:00
Jason Evans
a14712b4b8 Fix decay tests to all adapt to nstime_monotonic(). 2016-10-11 15:49:55 -07:00
Jason Evans
45a5bf6772 Do not advance decay epoch when time goes backwards.
Instead, move the epoch backward in time.  Additionally, add
nstime_monotonic() and use it in debug builds to assert that time only
goes backward if nstime_update() is using a non-monotonic time source.
2016-10-10 22:31:37 -07:00
Jason Evans
94e7ffa979 Refactor arena->decay_* into arena->decay.* (arena_decay_t). 2016-10-10 22:22:59 -07:00
Jason Evans
b732c395b7 Refine nstime_update().
Add missing #include <time.h>.  The critical time facilities appear to
have been transitively included via unistd.h and sys/time.h, but in
principle this omission was capable of having caused
clock_gettime(CLOCK_MONOTONIC, ...) to have been overlooked in favor of
gettimeofday(), which in turn could cause spurious non-monotonic time
updates.

Refactor nstime_get() out of nstime_update() and add configure tests for
all variants.

Add CLOCK_MONOTONIC_RAW support (Linux-specific) and
mach_absolute_time() support (OS X-specific).

Do not fall back to clock_gettime(CLOCK_REALTIME, ...).  This was a
fragile Linux-specific workaround, which we're unlikely to use at all
now that clock_gettime(CLOCK_MONOTONIC_RAW, ...) is supported, and if we
have no choice besides non-monotonic clocks, gettimeofday() is only
incrementally worse.
2016-10-10 11:40:46 -07:00
Jason Evans
5d8db15db9 Simplify run quantization. 2016-10-06 15:58:38 -07:00
Jason Evans
f193fd80cf Refactor runs_avail.
Use pszind_t size classes rather than szind_t size classes, and always
reserve space for NPSIZES elements.  This removes unused heaps that are
not multiples of the page size, and adds (currently) unused heaps for
all huge size classes, with the immediate benefit that the size of
arena_t allocations is constant (no longer dependent on chunk size).
2016-10-04 19:48:50 -07:00
Jason Evans
1abb49f09d Implement pz2ind(), pind2sz(), and psz2u().
These compute size classes and indices similarly to size2index(),
index2size() and s2u(), respectively, but using the subset of size
classes that are multiples of the page size.  Note that pszind_t and
szind_t are not interchangeable.
2016-10-04 16:29:19 -07:00
Jason Evans
bcd5424b1c Use TSDN_NULL rather than NULL as appropriate. 2016-10-04 15:56:56 -07:00
Jason Evans
c19b48fe73 Fix a typo. 2016-10-04 15:56:26 -07:00
Mike Hommey
af33e9a597 Define 64-bits atomics unconditionally
They are used on all platforms in prng.h.
2016-10-04 12:18:14 -07:00
Jason Evans
79647fe465 Close file descriptor after reading "/proc/sys/vm/overcommit_memory".
This bug was introduced by c2f970c32b
(Modify pages_map() to support mapping uncommitted virtual memory.).

This resolves #399.
2016-09-26 15:58:44 -07:00
Mike Hommey
3bb044c807 Add an AppVeyor config
This builds jemalloc and runs all checks with:
- MSVC 2015 64-bits
- MSVC 2015 32-bits
- MINGW64 (from msys2)
- MINGW32 (from msys2)

Normally, AppVeyor configs are named appveyor.yml, but it is possible to
configure the .yml file name in the AppVeyor project settings such that
the file stays "hidden", like typical travis configs.
2016-09-26 15:47:41 -07:00
Mike Hommey
43d4d7c373 Add Travis-CI configuration 2016-09-26 15:47:29 -07:00
Thomas Köckerbauer
92009b19d6 use install command determined by configure 2016-09-26 15:43:07 -07:00
Bai
15da5f5d9d Readme.txt error for building in the Windows
The command can't work using sh -C sh -c "./autogen.sh CC=cl --enable-lazy-lock=no". 
Change the position of the colon, the command of autogen work.
2016-09-26 15:35:30 -07:00
Eric Le Bihan
b54c0c2925 Fix LG_QUANTUM definition for sparc64
GCC 4.9.3 cross-compiled for sparc64 defines __sparc_v9__, not
__sparc64__ nor __sparcv9. This prevents LG_QUANTUM from being defined
properly. Adding this new value to the check solves the issue.
2016-09-26 15:14:59 -07:00
Elliot Ronaghan
c128167bca Disable irrelevant Cray compiler warnings if cc-silence is enabled
Cray is pretty warning-happy, so disable ones that aren't helpful. Each warning
has a numeric value instead of having named flags to disable specific warnings.
Disable warnings 128 and 1357.

128:  Ignore unreachable code warning. Cray warns about `not_reached()` not
      being reachable in a couple of places because it detects that some loops
      will never terminate.

1357: Ignore warning about redefinition of malloc and friends

With this patch, Cray 8.4.0 and 8.5.1 build cleanly and pass `make check`
2016-09-26 11:18:18 -07:00
Elliot Ronaghan
4b52518398 Add Cray compiler's equivalent of -Werror before __attribute__ checks
Cray uses -herror_on_warning instead of -Werror. Use it everywhere -Werror is
currently used for __attribute__ checks so configure actually detects they're
not supported.
2016-09-26 11:18:18 -07:00
Elliot Ronaghan
1d42a99027 Disable automatic dependency generation for the Cray compiler
Cray only supports `-M` for generating dependency files. It does not support
`-MM` or `-MT`, so don't try to use them. I just reused the existing mechanism
for turning auto-dependency generation off (`CC_MM=`), but it might be more
principled to add a configure test to check if the compiler supports `-MM` and
`-MT`, instead of manually tracking which compilers don't support those flags.
2016-09-26 11:18:18 -07:00
Elliot Ronaghan
8701bc7079 Add initial support for building with the cray compiler
Get jemalloc building and passing `make check_unit` with cray 8.4. An inlining
bug in 8.4 results in internal errors while trying to build jemalloc. This has
already been reported and fixed for the 8.5 release.

In order to work around the inlining bug, disable gnu compatibility and limit
ipa optimizations.

I copied the msvc compiler check for cray, but note that we perform the test
even if we think we're using gcc because cray pretends to be gcc if `-hgnu`
(which is enabled by default) is used. I couldn't come up with a principled way
to check for the inlining bug, so instead I just checked compiler versions.

The build had lots of warnings I need to address and cray doesn't support -MM
or -MT for dependency tracking, so I had to do `make CC_MM=`.
2016-09-26 11:18:18 -07:00
Elliot Ronaghan
b770d2da1d Fix librt detection when using a Cray compiler wrapper
The Cray compiler wrappers will often add `-lrt` to the base compiler with
`-static` linking (the default at most sites.) However, `-lrt` isn't
automatically added with `-dynamic`. This means that if jemalloc was built with
`-static`, but then used in a program with `-dynamic` jemalloc won't have
detected that librt is a dependency.

The integration and stress tests use -dynamic, which is causing undefined
references to clock_gettime().

This just adds an extra check for librt (ignoring the autoconf cache) with
`-dynamic` thrown. It also stops filtering librt from the integration tests.

With this `make check` passes for:
 - PrgEnv-gnu
 - PrgEnv-intel
 - PrgEnv-pgi

PrgEnv-cray still needs more work (will be in a separate patch.)
2016-09-26 11:11:55 -07:00
Elliot Ronaghan
3573fb93ce Add -dynamic for integration and stress tests with Cray compiler wrappers
Cray systems come with compiler wrappers to simplify building parallel
applications. CC is the C++ wrapper, and cc is the C wrapper.

The wrappers call the base {Cray, Intel, PGI, or GNU} compiler with vendor
specific flags. The "Programming Environment" (prgenv) that's currently loaded
determines the base compiler. e.g. compiling with gnu looks something like:

    module load PrgEnv-gnu
    cc hello.c

On most systems the wrappers defaults to `-static` mode, which causes them to
only look for static libraries, and not for any dynamic ones (even if the
dynamic version was explicitly listed.)

The integration and stress tests expect to be using the .so, so we have to run
the with -dynamic so that wrapper will find/use the .so.
2016-09-26 11:11:55 -07:00
Elliot Ronaghan
5acef864f2 Don't use compact red-black trees with the pgi compiler
Some bug (either in the red-black tree code, or in the pgi compiler) seems to
cause red-black trees to become unbalanced. This issue seems to go away if we
don't use compact red-black trees. Since red-black trees don't seem to be used
much anymore, I opted for what seems to be an easy fix here instead of digging
in and trying to find the root cause of the bug.

Some context in case it's helpful:

I experienced a ton of segfaults while using pgi as Chapel's target compiler
with jemalloc 4.0.4. The little bit of debugging I did pointed me somewhere
deep in red-black tree manipulation, but I didn't get a chance to investigate
further. It looks like 4.2.0 replaced most uses of red-black trees with
pairing-heaps, which seems to avoid whatever bug I was hitting.

However, `make check_unit` was still failing on the rb test, so I figured the
core issue was just being masked. Here's the `make check_unit` failure:

```sh
=== test/unit/rb ===
test_rb_empty: pass
tree_recurse:test/unit/rb.c:90: Failed assertion: (((_Bool) (((uintptr_t) (left_node)->link.rbn_right_red) & ((size_t)1)))) == (false) --> true != false: Node should be black
test_rb_random:test/unit/rb.c:274: Failed assertion: (imbalances) == (0) --> 1 != 0: Tree is unbalanced
tree_recurse:test/unit/rb.c:90: Failed assertion: (((_Bool) (((uintptr_t) (left_node)->link.rbn_right_red) & ((size_t)1)))) == (false) --> true != false: Node should be black
test_rb_random:test/unit/rb.c:274: Failed assertion: (imbalances) == (0) --> 1 != 0: Tree is unbalanced
node_remove:test/unit/rb.c:190: Failed assertion: (imbalances) == (0) --> 2 != 0: Tree is unbalanced
<jemalloc>: test/unit/rb.c:43: Failed assertion: "pathp[-1].cmp < 0"
test/test.sh: line 22: 12926 Aborted
Test harness error
```

While starting to debug I saw the RB_COMPACT option and decided to check if
turning that off resolved the bug. It seems to have fixed it (`make check_unit`
passes and the segfaults under Chapel are gone) so it seems like on okay
work-around. I'd imagine this has performance implications for red-black trees
under pgi, but if they're not going to be used much anymore it's probably not a
big deal.
2016-09-26 11:08:45 -07:00
Elliot Ronaghan
50a865e15a Work around a weird pgi bug in test/unit/math.c
pgi fails to compile math.c, reporting that `-INFINITY` in `pt_norm_expected[]`
is a "Non-constant" expression. A simplified version of this failure is:

```c
#include <math.h>

static double inf1, inf2 = INFINITY;  // no complaints
static double inf3 = INFINITY;        // suddenly INFINITY is "Non-constant"

int main() { }
```

```sh
PGC-S-0074-Non-constant expression in initializer (t.c: 4)
```

pgi errors on the declaration of inf3, and will compile fine if that line is
removed. I've reported this bug to pgi, but in the meantime I just switched to
using (DBL_MAX + DBL_MAX) to work around this bug.
2016-09-26 11:08:45 -07:00
Jason Evans
57cddffca6 Formatting fixes. 2016-09-26 11:01:59 -07:00
Mike Hommey
11b5da7533 Change how the default zone is found
On OSX 10.12, malloc_default_zone returns a special zone that is not
present in the list of registered zones. That zone uses a "lite zone"
if one is present (apparently enabled when malloc stack logging is
enabled), or the first registered zone otherwise. In practice this
means unless malloc stack logging is enabled, the first registered
zone is the default.

So get the list of zones to get the first one, instead of relying on
malloc_default_zone.
2016-09-26 11:01:37 -07:00
Elliot Ronaghan
38a96f07ac Fix a bug in __builtin_unreachable configure check
In 1167e9e, I accidentally tested je_cv_gcc_builtin_ffsl instead of
je_cv_gcc_builtin_unreachable (copy-paste error), which meant that
JEMALLOC_INTERNAL_UNREACHABLE was always getting defined as abort even if
__builtin_unreachable support was detected.
2016-09-26 10:44:51 -07:00
Elliot Ronaghan
d1207f0d37 Check for __builtin_unreachable at configure time
Add a configure check for __builtin_unreachable instead of basing its
availability on the __GNUC__ version. On OS X using gcc (a real gcc, not the
bundled version that's just a gcc front-end) leads to a linker assertion:

    https://github.com/jemalloc/jemalloc/issues/266

It turns out that this is caused by a gcc bug resulting from the use of
__builtin_unreachable():

    https://gcc.gnu.org/bugzilla/show_bug.cgi?id=57438

To work around this bug, check that __builtin_unreachable() actually works at
configure time, and if it doesn't use abort() instead. The check is based on
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=57438#c21.

With this `make check` passes with a homebrew installed gcc-5 and gcc-6.
2016-09-26 10:44:37 -07:00
Elliot Ronaghan
a6a8e40f7d Fix a valgrind regression in chunk_recycle()
Fix a latent valgrind bug exposed by d412624b25
(Move retaining out of default chunk hooks).
2016-09-26 10:30:57 -07:00
Qi Wang
57ed894f8a Fix arena_bind().
When tsd is not in nominal state (e.g. during thread termination), we
should not increment nthreads.
2016-09-23 14:39:29 -07:00
Jason Evans
9ebbfca93f Change html manual encoding to UTF-8.
This works around GitHub's broken automatic reformatting from ISO-8859-1
to UTF-8 when serving static html.

Remove <parameter/> from e.g. <function>malloc<parameter/></function>,
add a custom template that does not append parentheses, and manually
specify them, e.g. <function>malloc()</function>.  This works around
apparently broken XSL formatting that causes <code/> to be emitted in
html (rather than <code></code>, or better yet, nothing).
2016-09-12 16:44:33 -07:00
Jason Evans
3de0353352 Merge branch. 2016-06-08 11:41:24 -07:00
Jason Evans
5271b673b2 Update ChangeLog for 4.2.1. 2016-06-08 10:20:10 -07:00
Jason Evans
fa09fe798a Fix rallocx() sampling code to not eagerly commit sampler update.
rallocx() for an alignment-constrained request may end up with a
smaller-than-worst-case size if in-place reallocation succeeds due to
serendipitous alignment.  In such cases, sampling may not happen.
2016-06-08 10:14:25 -07:00
Jason Evans
20cd2de5ef Add a missing prof_alloc_rollback() call.
In the case where prof_alloc_prep() is called with an over-estimate of
allocation size, and sampling doesn't end up being triggered, the tctx
must be discarded.
2016-06-08 10:12:38 -07:00
Jason Evans
a7fdcc8b09 Fix opt_zero-triggered in-place huge reallocation zeroing.
Fix huge_ralloc_no_move_expand() to update the extent's zeroed attribute
based on the intersection of the previous value and that of the newly
merged trailing extent.
2016-06-08 10:10:08 -07:00
Elliot Ronaghan
c7d5298027 Fix a Valgrind regression in chunk_alloc_wrapper().
This regression was caused by d412624b25
(Move retaining out of default chunk hooks).
2016-06-07 14:30:39 -07:00
Elliot Ronaghan
9de0094e6e Fix a Valgrind regression in calloc().
This regression was caused by 3ef51d7f73
(Optimize the fast paths of calloc() and [m,d,sd]allocx().).
2016-06-07 14:27:24 -07:00
Jason Evans
05a9e4ac65 Fix potential VM map fragmentation regression.
Revert 245ae6036c (Support --with-lg-page
values larger than actual page size.), because it could cause VM map
fragmentation if the kernel grows mmap()ed memory downward.

This resolves #391.
2016-06-07 14:21:21 -07:00
Elliot Ronaghan
48384dc2d8 Fix mixed decl in nstime.c
Fix mixed decl in the gettimeofday() branch of nstime_update()
2016-06-07 14:08:19 -07:00
Jason Evans
09d7bdb314 Propagate tsdn to default chunk hooks.
This avoids bootstrapping issues for configurations that require
allocation during tsd initialization.

This resolves #390.
2016-06-07 14:00:58 -07:00
128 changed files with 6828 additions and 2513 deletions

42
.appveyor.yml Normal file
View File

@@ -0,0 +1,42 @@
version: '{build}'
environment:
matrix:
- MSYSTEM: MINGW64
CPU: x86_64
MSVC: amd64
- MSYSTEM: MINGW32
CPU: i686
MSVC: x86
- MSYSTEM: MINGW64
CPU: x86_64
- MSYSTEM: MINGW32
CPU: i686
- MSYSTEM: MINGW64
CPU: x86_64
MSVC: amd64
CONFIG_FLAGS: --enable-debug
- MSYSTEM: MINGW32
CPU: i686
MSVC: x86
CONFIG_FLAGS: --enable-debug
- MSYSTEM: MINGW64
CPU: x86_64
CONFIG_FLAGS: --enable-debug
- MSYSTEM: MINGW32
CPU: i686
CONFIG_FLAGS: --enable-debug
install:
- set PATH=c:\msys64\%MSYSTEM%\bin;c:\msys64\usr\bin;%PATH%
- if defined MSVC call "c:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" %MSVC%
- if defined MSVC pacman --noconfirm -Rsc mingw-w64-%CPU%-gcc gcc
- pacman --noconfirm -Suy mingw-w64-%CPU%-make
build_script:
- bash -c "autoconf"
- bash -c "./configure $CONFIG_FLAGS"
- mingw32-make -j3
- file lib/jemalloc.dll
- mingw32-make -j3 tests
- mingw32-make -k check

95
.travis.yml Normal file
View File

@@ -0,0 +1,95 @@
language: generic
matrix:
include:
- os: linux
env: CC=gcc COMPILER_FLAGS="" CONFIGURE_FLAGS=""
- os: osx
env: CC=gcc COMPILER_FLAGS="" CONFIGURE_FLAGS=""
- os: linux
env: CC=clang COMPILER_FLAGS="" CONFIGURE_FLAGS=""
- os: linux
env: CC=gcc COMPILER_FLAGS="-m32" CONFIGURE_FLAGS=""
addons:
apt:
packages:
- gcc-multilib
- os: linux
env: CC=gcc COMPILER_FLAGS="" CONFIGURE_FLAGS="--enable-debug"
- os: linux
env: CC=gcc COMPILER_FLAGS="" CONFIGURE_FLAGS="--enable-prof"
- os: linux
env: CC=gcc COMPILER_FLAGS="" CONFIGURE_FLAGS="--disable-stats"
- os: linux
env: CC=gcc COMPILER_FLAGS="" CONFIGURE_FLAGS="--disable-tcache"
- os: osx
env: CC=clang COMPILER_FLAGS="" CONFIGURE_FLAGS=""
- os: osx
env: CC=gcc COMPILER_FLAGS="-m32" CONFIGURE_FLAGS=""
- os: osx
env: CC=gcc COMPILER_FLAGS="" CONFIGURE_FLAGS="--enable-debug"
- os: osx
env: CC=gcc COMPILER_FLAGS="" CONFIGURE_FLAGS="--disable-stats"
- os: osx
env: CC=gcc COMPILER_FLAGS="" CONFIGURE_FLAGS="--disable-tcache"
- os: linux
env: CC=clang COMPILER_FLAGS="-m32" CONFIGURE_FLAGS=""
addons:
apt:
packages:
- gcc-multilib
- os: linux
env: CC=clang COMPILER_FLAGS="" CONFIGURE_FLAGS="--enable-debug"
- os: linux
env: CC=clang COMPILER_FLAGS="" CONFIGURE_FLAGS="--enable-prof"
- os: linux
env: CC=clang COMPILER_FLAGS="" CONFIGURE_FLAGS="--disable-stats"
- os: linux
env: CC=clang COMPILER_FLAGS="" CONFIGURE_FLAGS="--disable-tcache"
- os: linux
env: CC=gcc COMPILER_FLAGS="-m32" CONFIGURE_FLAGS="--enable-debug"
addons:
apt:
packages:
- gcc-multilib
- os: linux
env: CC=gcc COMPILER_FLAGS="-m32" CONFIGURE_FLAGS="--enable-prof"
addons:
apt:
packages:
- gcc-multilib
- os: linux
env: CC=gcc COMPILER_FLAGS="-m32" CONFIGURE_FLAGS="--disable-stats"
addons:
apt:
packages:
- gcc-multilib
- os: linux
env: CC=gcc COMPILER_FLAGS="-m32" CONFIGURE_FLAGS="--disable-tcache"
addons:
apt:
packages:
- gcc-multilib
- os: linux
env: CC=gcc COMPILER_FLAGS="" CONFIGURE_FLAGS="--enable-debug --enable-prof"
- os: linux
env: CC=gcc COMPILER_FLAGS="" CONFIGURE_FLAGS="--enable-debug --disable-stats"
- os: linux
env: CC=gcc COMPILER_FLAGS="" CONFIGURE_FLAGS="--enable-debug --disable-tcache"
- os: linux
env: CC=gcc COMPILER_FLAGS="" CONFIGURE_FLAGS="--enable-prof --disable-stats"
- os: linux
env: CC=gcc COMPILER_FLAGS="" CONFIGURE_FLAGS="--enable-prof --disable-tcache"
- os: linux
env: CC=gcc COMPILER_FLAGS="" CONFIGURE_FLAGS="--disable-stats --disable-tcache"
before_script:
- autoconf
- ./configure ${COMPILER_FLAGS:+ CC="$CC $COMPILER_FLAGS" } $CONFIGURE_FLAGS
- make -j3
- make -j3 tests
script:
- make check

128
ChangeLog
View File

@@ -4,11 +4,137 @@ brevity. Much more detail can be found in the git revision history:
https://github.com/jemalloc/jemalloc https://github.com/jemalloc/jemalloc
* 4.5.0 (February 28, 2017)
This is the first release to benefit from much broader continuous integration
testing, thanks to @davidtgoldblatt. Had we had this testing infrastructure
in place for prior releases, it would have caught all of the most serious
regressions fixed by this release.
New features:
- Add --disable-thp and the opt.thp to provide opt-out mechanisms for
transparent huge page integration. (@jasone)
- Update zone allocator integration to work with macOS 10.12. (@glandium)
- Restructure *CFLAGS configuration, so that CFLAGS behaves typically, and
EXTRA_CFLAGS provides a way to specify e.g. -Werror during building, but not
during configuration. (@jasone, @ronawho)
Bug fixes:
- Fix DSS (sbrk(2)-based) allocation. This regression was first released in
4.3.0. (@jasone)
- Handle race in per size class utilization computation. This functionality
was first released in 4.0.0. (@interwq)
- Fix lock order reversal during gdump. (@jasone)
- Fix-refactor tcache synchronization. This regression was first released in
4.0.0. (@jasone)
- Fix various JSON-formatted malloc_stats_print() bugs. This functionality
was first released in 4.3.0. (@jasone)
- Fix huge-aligned allocation. This regression was first released in 4.4.0.
(@jasone)
- When transparent huge page integration is enabled, detect what state pages
start in according to the kernel's current operating mode, and only convert
arena chunks to non-huge during purging if that is not their initial state.
This functionality was first released in 4.4.0. (@jasone)
- Fix lg_chunk clamping for the --enable-cache-oblivious --disable-fill case.
This regression was first released in 4.0.0. (@jasone, @428desmo)
- Properly detect sparc64 when building for Linux. (@glaubitz)
* 4.4.0 (December 3, 2016)
New features:
- Add configure support for *-*-linux-android. (@cferris1000, @jasone)
- Add the --disable-syscall configure option, for use on systems that place
security-motivated limitations on syscall(2). (@jasone)
- Add support for Debian GNU/kFreeBSD. (@thesam)
Optimizations:
- Add extent serial numbers and use them where appropriate as a sort key that
is higher priority than address, so that the allocation policy prefers older
extents. This tends to improve locality (decrease fragmentation) when
memory grows downward. (@jasone)
- Refactor madvise(2) configuration so that MADV_FREE is detected and utilized
on Linux 4.5 and newer. (@jasone)
- Mark partially purged arena chunks as non-huge-page. This improves
interaction with Linux's transparent huge page functionality. (@jasone)
Bug fixes:
- Fix size class computations for edge conditions involving extremely large
allocations. This regression was first released in 4.0.0. (@jasone,
@ingvarha)
- Remove overly restrictive assertions related to the cactive statistic. This
regression was first released in 4.1.0. (@jasone)
- Implement a more reliable detection scheme for os_unfair_lock on macOS.
(@jszakmeister)
* 4.3.1 (November 7, 2016)
Bug fixes:
- Fix a severe virtual memory leak. This regression was first released in
4.3.0. (@interwq, @jasone)
- Refactor atomic and prng APIs to restore support for 32-bit platforms that
use pre-C11 toolchains, e.g. FreeBSD's mips. (@jasone)
* 4.3.0 (November 4, 2016)
This is the first release that passes the test suite for multiple Windows
configurations, thanks in large part to @glandium setting up continuous
integration via AppVeyor (and Travis CI for Linux and OS X).
New features:
- Add "J" (JSON) support to malloc_stats_print(). (@jasone)
- Add Cray compiler support. (@ronawho)
Optimizations:
- Add/use adaptive spinning for bootstrapping and radix tree node
initialization. (@jasone)
Bug fixes:
- Fix large allocation to search starting in the optimal size class heap,
which can substantially reduce virtual memory churn and fragmentation. This
regression was first released in 4.0.0. (@mjp41, @jasone)
- Fix stats.arenas.<i>.nthreads accounting. (@interwq)
- Fix and simplify decay-based purging. (@jasone)
- Make DSS (sbrk(2)-related) operations lockless, which resolves potential
deadlocks during thread exit. (@jasone)
- Fix over-sized allocation of radix tree leaf nodes. (@mjp41, @ogaun,
@jasone)
- Fix over-sized allocation of arena_t (plus associated stats) data
structures. (@jasone, @interwq)
- Fix EXTRA_CFLAGS to not affect configuration. (@jasone)
- Fix a Valgrind integration bug. (@ronawho)
- Disallow 0x5a junk filling when running in Valgrind. (@jasone)
- Fix a file descriptor leak on Linux. This regression was first released in
4.2.0. (@vsarunas, @jasone)
- Fix static linking of jemalloc with glibc. (@djwatson)
- Use syscall(2) rather than {open,read,close}(2) during boot on Linux. This
works around other libraries' system call wrappers performing reentrant
allocation. (@kspinka, @Whissi, @jasone)
- Fix OS X default zone replacement to work with OS X 10.12. (@glandium,
@jasone)
- Fix cached memory management to avoid needless commit/decommit operations
during purging, which resolves permanent virtual memory map fragmentation
issues on Windows. (@mjp41, @jasone)
- Fix TSD fetches to avoid (recursive) allocation. This is relevant to
non-TLS and Windows configurations. (@jasone)
- Fix malloc_conf overriding to work on Windows. (@jasone)
- Forcibly disable lazy-lock on Windows (was forcibly *enabled*). (@jasone)
* 4.2.1 (June 8, 2016)
Bug fixes:
- Fix bootstrapping issues for configurations that require allocation during
tsd initialization (e.g. --disable-tls). (@cferris1000, @jasone)
- Fix gettimeofday() version of nstime_update(). (@ronawho)
- Fix Valgrind regressions in calloc() and chunk_alloc_wrapper(). (@ronawho)
- Fix potential VM map fragmentation regression. (@jasone)
- Fix opt_zero-triggered in-place huge reallocation zeroing. (@jasone)
- Fix heap profiling context leaks in reallocation edge cases. (@jasone)
* 4.2.0 (May 12, 2016) * 4.2.0 (May 12, 2016)
New features: New features:
- Add the arena.<i>.reset mallctl, which makes it possible to discard all of - Add the arena.<i>.reset mallctl, which makes it possible to discard all of
an arena's allocations in a single operation. (@jasone@) an arena's allocations in a single operation. (@jasone)
- Add the stats.retained and stats.arenas.<i>.retained statistics. (@jasone) - Add the stats.retained and stats.arenas.<i>.retained statistics. (@jasone)
- Add the --with-version configure option. (@jasone) - Add the --with-version configure option. (@jasone)
- Support --with-lg-page values larger than actual page size. (@jasone) - Support --with-lg-page values larger than actual page size. (@jasone)

38
INSTALL
View File

@@ -157,6 +157,13 @@ any of the following arguments (not a definitive list) to 'configure':
released in bulk, thus reducing the total number of mutex operations. See released in bulk, thus reducing the total number of mutex operations. See
the "opt.tcache" option for usage details. the "opt.tcache" option for usage details.
--disable-thp
Disable transparent huge page (THP) integration. On systems with THP
support, THPs are explicitly disabled as a side effect of unused dirty page
purging for chunks that back small and/or large allocations, because such
chunks typically comprise active, unused dirty, and untouched clean
pages.
--disable-munmap --disable-munmap
Disable virtual memory deallocation via munmap(2); instead keep track of Disable virtual memory deallocation via munmap(2); instead keep track of
the virtual memory for later use. munmap() is disabled by default (i.e. the virtual memory for later use. munmap() is disabled by default (i.e.
@@ -206,6 +213,11 @@ any of the following arguments (not a definitive list) to 'configure':
most extreme case increases physical memory usage for the 16 KiB size class most extreme case increases physical memory usage for the 16 KiB size class
to 20 KiB. to 20 KiB.
--disable-syscall
Disable use of syscall(2) rather than {open,read,write,close}(2). This is
intended as a workaround for systems that place security limitations on
syscall(2).
--with-xslroot=<path> --with-xslroot=<path>
Specify where to find DocBook XSL stylesheets when building the Specify where to find DocBook XSL stylesheets when building the
documentation. documentation.
@@ -301,17 +313,16 @@ The following environment variables (not a definitive list) impact configure's
behavior: behavior:
CFLAGS="?" CFLAGS="?"
Pass these flags to the compiler. You probably shouldn't define this unless Pass these flags to the C compiler. Any flags set by the configure script
you know what you are doing. (Use EXTRA_CFLAGS instead.) are prepended, which means explicitly set flags generally take precedence.
Take care when specifying flags such as -Werror, because configure tests may
be affected in undesirable ways.
EXTRA_CFLAGS="?" EXTRA_CFLAGS="?"
Append these flags to CFLAGS. This makes it possible to add flags such as Append these flags to CFLAGS, without passing them to the compiler during
-Werror, while allowing the configure script to determine what other flags configuration. This makes it possible to add flags such as -Werror, while
are appropriate for the specified configuration. allowing the configure script to determine what other flags are appropriate
for the specified configuration.
The configure script specifically checks whether an optimization flag (-O*)
is specified in EXTRA_CFLAGS, and refrains from specifying an optimization
level if it finds that one has already been specified.
CPPFLAGS="?" CPPFLAGS="?"
Pass these flags to the C preprocessor. Note that CFLAGS is not passed to Pass these flags to the C preprocessor. Note that CFLAGS is not passed to
@@ -327,6 +338,15 @@ LDFLAGS="?"
PATH="?" PATH="?"
'configure' uses this to find programs. 'configure' uses this to find programs.
In some cases it may be necessary to work around configuration results that do
not match reality. For example, Linux 4.5 added support for the MADV_FREE flag
to madvise(2), which can cause problems if building on a host with MADV_FREE
support and deploying to a target without. To work around this, use a cache
file to override the relevant configuration variable defined in configure.ac,
e.g.:
echo "je_cv_madv_free=no" > config.cache && ./configure -C
=== Advanced compilation ======================================================= === Advanced compilation =======================================================
To build only parts of jemalloc, use the following targets: To build only parts of jemalloc, use the following targets:

View File

@@ -24,7 +24,10 @@ abs_objroot := @abs_objroot@
# Build parameters. # Build parameters.
CPPFLAGS := @CPPFLAGS@ -I$(srcroot)include -I$(objroot)include CPPFLAGS := @CPPFLAGS@ -I$(srcroot)include -I$(objroot)include
CFLAGS := @CFLAGS@ CONFIGURE_CFLAGS := @CONFIGURE_CFLAGS@
SPECIFIED_CFLAGS := @SPECIFIED_CFLAGS@
EXTRA_CFLAGS := @EXTRA_CFLAGS@
CFLAGS := $(strip $(CONFIGURE_CFLAGS) $(SPECIFIED_CFLAGS) $(EXTRA_CFLAGS))
LDFLAGS := @LDFLAGS@ LDFLAGS := @LDFLAGS@
EXTRA_LDFLAGS := @EXTRA_LDFLAGS@ EXTRA_LDFLAGS := @EXTRA_LDFLAGS@
LIBS := @LIBS@ LIBS := @LIBS@
@@ -52,15 +55,19 @@ enable_prof := @enable_prof@
enable_valgrind := @enable_valgrind@ enable_valgrind := @enable_valgrind@
enable_zone_allocator := @enable_zone_allocator@ enable_zone_allocator := @enable_zone_allocator@
MALLOC_CONF := @JEMALLOC_CPREFIX@MALLOC_CONF MALLOC_CONF := @JEMALLOC_CPREFIX@MALLOC_CONF
link_whole_archive := @link_whole_archive@
DSO_LDFLAGS = @DSO_LDFLAGS@ DSO_LDFLAGS = @DSO_LDFLAGS@
SOREV = @SOREV@ SOREV = @SOREV@
PIC_CFLAGS = @PIC_CFLAGS@ PIC_CFLAGS = @PIC_CFLAGS@
CTARGET = @CTARGET@ CTARGET = @CTARGET@
LDTARGET = @LDTARGET@ LDTARGET = @LDTARGET@
TEST_LD_MODE = @TEST_LD_MODE@
MKLIB = @MKLIB@ MKLIB = @MKLIB@
AR = @AR@ AR = @AR@
ARFLAGS = @ARFLAGS@ ARFLAGS = @ARFLAGS@
CC_MM = @CC_MM@ CC_MM = @CC_MM@
LM := @LM@
INSTALL = @INSTALL@
ifeq (macho, $(ABI)) ifeq (macho, $(ABI))
TEST_LIBRARY_PATH := DYLD_FALLBACK_LIBRARY_PATH="$(objroot)lib" TEST_LIBRARY_PATH := DYLD_FALLBACK_LIBRARY_PATH="$(objroot)lib"
@@ -99,6 +106,7 @@ C_SRCS := $(srcroot)src/jemalloc.c \
$(srcroot)src/quarantine.c \ $(srcroot)src/quarantine.c \
$(srcroot)src/rtree.c \ $(srcroot)src/rtree.c \
$(srcroot)src/stats.c \ $(srcroot)src/stats.c \
$(srcroot)src/spin.c \
$(srcroot)src/tcache.c \ $(srcroot)src/tcache.c \
$(srcroot)src/ticker.c \ $(srcroot)src/ticker.c \
$(srcroot)src/tsd.c \ $(srcroot)src/tsd.c \
@@ -122,6 +130,11 @@ DSOS := $(objroot)lib/$(LIBJEMALLOC).$(SOREV)
ifneq ($(SOREV),$(SO)) ifneq ($(SOREV),$(SO))
DSOS += $(objroot)lib/$(LIBJEMALLOC).$(SO) DSOS += $(objroot)lib/$(LIBJEMALLOC).$(SO)
endif endif
ifeq (1, $(link_whole_archive))
LJEMALLOC := -Wl,--whole-archive -L$(objroot)lib -l$(LIBJEMALLOC) -Wl,--no-whole-archive
else
LJEMALLOC := $(objroot)lib/$(LIBJEMALLOC).$(IMPORTLIB)
endif
PC := $(objroot)jemalloc.pc PC := $(objroot)jemalloc.pc
MAN3 := $(objroot)doc/jemalloc$(install_suffix).3 MAN3 := $(objroot)doc/jemalloc$(install_suffix).3
DOCS_XML := $(objroot)doc/jemalloc$(install_suffix).xml DOCS_XML := $(objroot)doc/jemalloc$(install_suffix).xml
@@ -133,7 +146,11 @@ C_TESTLIB_SRCS := $(srcroot)test/src/btalloc.c $(srcroot)test/src/btalloc_0.c \
$(srcroot)test/src/mtx.c $(srcroot)test/src/mq.c \ $(srcroot)test/src/mtx.c $(srcroot)test/src/mq.c \
$(srcroot)test/src/SFMT.c $(srcroot)test/src/test.c \ $(srcroot)test/src/SFMT.c $(srcroot)test/src/test.c \
$(srcroot)test/src/thd.c $(srcroot)test/src/timer.c $(srcroot)test/src/thd.c $(srcroot)test/src/timer.c
ifeq (1, $(link_whole_archive))
C_UTIL_INTEGRATION_SRCS :=
else
C_UTIL_INTEGRATION_SRCS := $(srcroot)src/nstime.c $(srcroot)src/util.c C_UTIL_INTEGRATION_SRCS := $(srcroot)src/nstime.c $(srcroot)src/util.c
endif
TESTS_UNIT := \ TESTS_UNIT := \
$(srcroot)test/unit/a0.c \ $(srcroot)test/unit/a0.c \
$(srcroot)test/unit/arena_reset.c \ $(srcroot)test/unit/arena_reset.c \
@@ -141,6 +158,7 @@ TESTS_UNIT := \
$(srcroot)test/unit/bitmap.c \ $(srcroot)test/unit/bitmap.c \
$(srcroot)test/unit/ckh.c \ $(srcroot)test/unit/ckh.c \
$(srcroot)test/unit/decay.c \ $(srcroot)test/unit/decay.c \
$(srcroot)test/unit/extent_quantize.c \
$(srcroot)test/unit/fork.c \ $(srcroot)test/unit/fork.c \
$(srcroot)test/unit/hash.c \ $(srcroot)test/unit/hash.c \
$(srcroot)test/unit/junk.c \ $(srcroot)test/unit/junk.c \
@@ -151,6 +169,8 @@ TESTS_UNIT := \
$(srcroot)test/unit/math.c \ $(srcroot)test/unit/math.c \
$(srcroot)test/unit/mq.c \ $(srcroot)test/unit/mq.c \
$(srcroot)test/unit/mtx.c \ $(srcroot)test/unit/mtx.c \
$(srcroot)test/unit/pack.c \
$(srcroot)test/unit/pages.c \
$(srcroot)test/unit/ph.c \ $(srcroot)test/unit/ph.c \
$(srcroot)test/unit/prng.c \ $(srcroot)test/unit/prng.c \
$(srcroot)test/unit/prof_accum.c \ $(srcroot)test/unit/prof_accum.c \
@@ -169,6 +189,7 @@ TESTS_UNIT := \
$(srcroot)test/unit/size_classes.c \ $(srcroot)test/unit/size_classes.c \
$(srcroot)test/unit/smoothstep.c \ $(srcroot)test/unit/smoothstep.c \
$(srcroot)test/unit/stats.c \ $(srcroot)test/unit/stats.c \
$(srcroot)test/unit/stats_print.c \
$(srcroot)test/unit/ticker.c \ $(srcroot)test/unit/ticker.c \
$(srcroot)test/unit/nstime.c \ $(srcroot)test/unit/nstime.c \
$(srcroot)test/unit/tsd.c \ $(srcroot)test/unit/tsd.c \
@@ -295,69 +316,69 @@ $(STATIC_LIBS):
$(objroot)test/unit/%$(EXE): $(objroot)test/unit/%.$(O) $(TESTS_UNIT_LINK_OBJS) $(C_JET_OBJS) $(C_TESTLIB_UNIT_OBJS) $(objroot)test/unit/%$(EXE): $(objroot)test/unit/%.$(O) $(TESTS_UNIT_LINK_OBJS) $(C_JET_OBJS) $(C_TESTLIB_UNIT_OBJS)
@mkdir -p $(@D) @mkdir -p $(@D)
$(CC) $(LDTARGET) $(filter %.$(O),$^) $(call RPATH,$(objroot)lib) $(LDFLAGS) $(filter-out -lm,$(LIBS)) -lm $(EXTRA_LDFLAGS) $(CC) $(LDTARGET) $(filter %.$(O),$^) $(call RPATH,$(objroot)lib) $(LDFLAGS) $(filter-out -lm,$(LIBS)) $(LM) $(EXTRA_LDFLAGS)
$(objroot)test/integration/%$(EXE): $(objroot)test/integration/%.$(O) $(C_TESTLIB_INTEGRATION_OBJS) $(C_UTIL_INTEGRATION_OBJS) $(objroot)lib/$(LIBJEMALLOC).$(IMPORTLIB) $(objroot)test/integration/%$(EXE): $(objroot)test/integration/%.$(O) $(C_TESTLIB_INTEGRATION_OBJS) $(C_UTIL_INTEGRATION_OBJS) $(objroot)lib/$(LIBJEMALLOC).$(IMPORTLIB)
@mkdir -p $(@D) @mkdir -p $(@D)
$(CC) $(LDTARGET) $(filter %.$(O),$^) $(call RPATH,$(objroot)lib) $(objroot)lib/$(LIBJEMALLOC).$(IMPORTLIB) $(LDFLAGS) $(filter-out -lm,$(filter -lpthread,$(LIBS))) -lm $(EXTRA_LDFLAGS) $(CC) $(TEST_LD_MODE) $(LDTARGET) $(filter %.$(O),$^) $(call RPATH,$(objroot)lib) $(LJEMALLOC) $(LDFLAGS) $(filter-out -lm,$(filter -lrt -lpthread,$(LIBS))) $(LM) $(EXTRA_LDFLAGS)
$(objroot)test/stress/%$(EXE): $(objroot)test/stress/%.$(O) $(C_JET_OBJS) $(C_TESTLIB_STRESS_OBJS) $(objroot)lib/$(LIBJEMALLOC).$(IMPORTLIB) $(objroot)test/stress/%$(EXE): $(objroot)test/stress/%.$(O) $(C_JET_OBJS) $(C_TESTLIB_STRESS_OBJS) $(objroot)lib/$(LIBJEMALLOC).$(IMPORTLIB)
@mkdir -p $(@D) @mkdir -p $(@D)
$(CC) $(LDTARGET) $(filter %.$(O),$^) $(call RPATH,$(objroot)lib) $(objroot)lib/$(LIBJEMALLOC).$(IMPORTLIB) $(LDFLAGS) $(filter-out -lm,$(LIBS)) -lm $(EXTRA_LDFLAGS) $(CC) $(TEST_LD_MODE) $(LDTARGET) $(filter %.$(O),$^) $(call RPATH,$(objroot)lib) $(objroot)lib/$(LIBJEMALLOC).$(IMPORTLIB) $(LDFLAGS) $(filter-out -lm,$(LIBS)) $(LM) $(EXTRA_LDFLAGS)
build_lib_shared: $(DSOS) build_lib_shared: $(DSOS)
build_lib_static: $(STATIC_LIBS) build_lib_static: $(STATIC_LIBS)
build_lib: build_lib_shared build_lib_static build_lib: build_lib_shared build_lib_static
install_bin: install_bin:
install -d $(BINDIR) $(INSTALL) -d $(BINDIR)
@for b in $(BINS); do \ @for b in $(BINS); do \
echo "install -m 755 $$b $(BINDIR)"; \ echo "$(INSTALL) -m 755 $$b $(BINDIR)"; \
install -m 755 $$b $(BINDIR); \ $(INSTALL) -m 755 $$b $(BINDIR); \
done done
install_include: install_include:
install -d $(INCLUDEDIR)/jemalloc $(INSTALL) -d $(INCLUDEDIR)/jemalloc
@for h in $(C_HDRS); do \ @for h in $(C_HDRS); do \
echo "install -m 644 $$h $(INCLUDEDIR)/jemalloc"; \ echo "$(INSTALL) -m 644 $$h $(INCLUDEDIR)/jemalloc"; \
install -m 644 $$h $(INCLUDEDIR)/jemalloc; \ $(INSTALL) -m 644 $$h $(INCLUDEDIR)/jemalloc; \
done done
install_lib_shared: $(DSOS) install_lib_shared: $(DSOS)
install -d $(LIBDIR) $(INSTALL) -d $(LIBDIR)
install -m 755 $(objroot)lib/$(LIBJEMALLOC).$(SOREV) $(LIBDIR) $(INSTALL) -m 755 $(objroot)lib/$(LIBJEMALLOC).$(SOREV) $(LIBDIR)
ifneq ($(SOREV),$(SO)) ifneq ($(SOREV),$(SO))
ln -sf $(LIBJEMALLOC).$(SOREV) $(LIBDIR)/$(LIBJEMALLOC).$(SO) ln -sf $(LIBJEMALLOC).$(SOREV) $(LIBDIR)/$(LIBJEMALLOC).$(SO)
endif endif
install_lib_static: $(STATIC_LIBS) install_lib_static: $(STATIC_LIBS)
install -d $(LIBDIR) $(INSTALL) -d $(LIBDIR)
@for l in $(STATIC_LIBS); do \ @for l in $(STATIC_LIBS); do \
echo "install -m 755 $$l $(LIBDIR)"; \ echo "$(INSTALL) -m 755 $$l $(LIBDIR)"; \
install -m 755 $$l $(LIBDIR); \ $(INSTALL) -m 755 $$l $(LIBDIR); \
done done
install_lib_pc: $(PC) install_lib_pc: $(PC)
install -d $(LIBDIR)/pkgconfig $(INSTALL) -d $(LIBDIR)/pkgconfig
@for l in $(PC); do \ @for l in $(PC); do \
echo "install -m 644 $$l $(LIBDIR)/pkgconfig"; \ echo "$(INSTALL) -m 644 $$l $(LIBDIR)/pkgconfig"; \
install -m 644 $$l $(LIBDIR)/pkgconfig; \ $(INSTALL) -m 644 $$l $(LIBDIR)/pkgconfig; \
done done
install_lib: install_lib_shared install_lib_static install_lib_pc install_lib: install_lib_shared install_lib_static install_lib_pc
install_doc_html: install_doc_html:
install -d $(DATADIR)/doc/jemalloc$(install_suffix) $(INSTALL) -d $(DATADIR)/doc/jemalloc$(install_suffix)
@for d in $(DOCS_HTML); do \ @for d in $(DOCS_HTML); do \
echo "install -m 644 $$d $(DATADIR)/doc/jemalloc$(install_suffix)"; \ echo "$(INSTALL) -m 644 $$d $(DATADIR)/doc/jemalloc$(install_suffix)"; \
install -m 644 $$d $(DATADIR)/doc/jemalloc$(install_suffix); \ $(INSTALL) -m 644 $$d $(DATADIR)/doc/jemalloc$(install_suffix); \
done done
install_doc_man: install_doc_man:
install -d $(MANDIR)/man3 $(INSTALL) -d $(MANDIR)/man3
@for d in $(DOCS_MAN3); do \ @for d in $(DOCS_MAN3); do \
echo "install -m 644 $$d $(MANDIR)/man3"; \ echo "$(INSTALL) -m 644 $$d $(MANDIR)/man3"; \
install -m 644 $$d $(MANDIR)/man3; \ $(INSTALL) -m 644 $$d $(MANDIR)/man3; \
done done
install_doc: install_doc_html install_doc_man install_doc: install_doc_html install_doc_man

2
README
View File

@@ -17,4 +17,4 @@ jemalloc.
The ChangeLog file contains a brief summary of changes for each release. The ChangeLog file contains a brief summary of changes for each release.
URL: http://www.canonware.com/jemalloc/ URL: http://jemalloc.net/

174
build-aux/config.guess vendored
View File

@@ -1,8 +1,8 @@
#! /bin/sh #! /bin/sh
# Attempt to guess a canonical system name. # Attempt to guess a canonical system name.
# Copyright 1992-2014 Free Software Foundation, Inc. # Copyright 1992-2016 Free Software Foundation, Inc.
timestamp='2014-03-23' timestamp='2016-10-02'
# This file is free software; you can redistribute it and/or modify it # This file is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by # under the terms of the GNU General Public License as published by
@@ -24,12 +24,12 @@ timestamp='2014-03-23'
# program. This Exception is an additional permission under section 7 # program. This Exception is an additional permission under section 7
# of the GNU General Public License, version 3 ("GPLv3"). # of the GNU General Public License, version 3 ("GPLv3").
# #
# Originally written by Per Bothner. # Originally written by Per Bothner; maintained since 2000 by Ben Elliston.
# #
# You can get the latest version of this script from: # You can get the latest version of this script from:
# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD # http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess
# #
# Please send patches with a ChangeLog entry to config-patches@gnu.org. # Please send patches to <config-patches@gnu.org>.
me=`echo "$0" | sed -e 's,.*/,,'` me=`echo "$0" | sed -e 's,.*/,,'`
@@ -50,7 +50,7 @@ version="\
GNU config.guess ($timestamp) GNU config.guess ($timestamp)
Originally written by Per Bothner. Originally written by Per Bothner.
Copyright 1992-2014 Free Software Foundation, Inc. Copyright 1992-2016 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
@@ -168,19 +168,29 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
# Note: NetBSD doesn't particularly care about the vendor # Note: NetBSD doesn't particularly care about the vendor
# portion of the name. We always set it to "unknown". # portion of the name. We always set it to "unknown".
sysctl="sysctl -n hw.machine_arch" sysctl="sysctl -n hw.machine_arch"
UNAME_MACHINE_ARCH=`(/sbin/$sysctl 2>/dev/null || \ UNAME_MACHINE_ARCH=`(uname -p 2>/dev/null || \
/usr/sbin/$sysctl 2>/dev/null || echo unknown)` /sbin/$sysctl 2>/dev/null || \
/usr/sbin/$sysctl 2>/dev/null || \
echo unknown)`
case "${UNAME_MACHINE_ARCH}" in case "${UNAME_MACHINE_ARCH}" in
armeb) machine=armeb-unknown ;; armeb) machine=armeb-unknown ;;
arm*) machine=arm-unknown ;; arm*) machine=arm-unknown ;;
sh3el) machine=shl-unknown ;; sh3el) machine=shl-unknown ;;
sh3eb) machine=sh-unknown ;; sh3eb) machine=sh-unknown ;;
sh5el) machine=sh5le-unknown ;; sh5el) machine=sh5le-unknown ;;
earmv*)
arch=`echo ${UNAME_MACHINE_ARCH} | sed -e 's,^e\(armv[0-9]\).*$,\1,'`
endian=`echo ${UNAME_MACHINE_ARCH} | sed -ne 's,^.*\(eb\)$,\1,p'`
machine=${arch}${endian}-unknown
;;
*) machine=${UNAME_MACHINE_ARCH}-unknown ;; *) machine=${UNAME_MACHINE_ARCH}-unknown ;;
esac esac
# The Operating System including object format, if it has switched # The Operating System including object format, if it has switched
# to ELF recently, or will in the future. # to ELF recently (or will in the future) and ABI.
case "${UNAME_MACHINE_ARCH}" in case "${UNAME_MACHINE_ARCH}" in
earm*)
os=netbsdelf
;;
arm*|i386|m68k|ns32k|sh3*|sparc|vax) arm*|i386|m68k|ns32k|sh3*|sparc|vax)
eval $set_cc_for_build eval $set_cc_for_build
if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \ if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \
@@ -197,6 +207,13 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
os=netbsd os=netbsd
;; ;;
esac esac
# Determine ABI tags.
case "${UNAME_MACHINE_ARCH}" in
earm*)
expr='s/^earmv[0-9]/-eabi/;s/eb$//'
abi=`echo ${UNAME_MACHINE_ARCH} | sed -e "$expr"`
;;
esac
# The OS release # The OS release
# Debian GNU/NetBSD machines have a different userland, and # Debian GNU/NetBSD machines have a different userland, and
# thus, need a distinct triplet. However, they do not need # thus, need a distinct triplet. However, they do not need
@@ -207,13 +224,13 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
release='-gnu' release='-gnu'
;; ;;
*) *)
release=`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'` release=`echo ${UNAME_RELEASE} | sed -e 's/[-_].*//' | cut -d. -f1,2`
;; ;;
esac esac
# Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM: # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM:
# contains redundant information, the shorter form: # contains redundant information, the shorter form:
# CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used. # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used.
echo "${machine}-${os}${release}" echo "${machine}-${os}${release}${abi}"
exit ;; exit ;;
*:Bitrig:*:*) *:Bitrig:*:*)
UNAME_MACHINE_ARCH=`arch | sed 's/Bitrig.//'` UNAME_MACHINE_ARCH=`arch | sed 's/Bitrig.//'`
@@ -223,6 +240,10 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'` UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'`
echo ${UNAME_MACHINE_ARCH}-unknown-openbsd${UNAME_RELEASE} echo ${UNAME_MACHINE_ARCH}-unknown-openbsd${UNAME_RELEASE}
exit ;; exit ;;
*:LibertyBSD:*:*)
UNAME_MACHINE_ARCH=`arch | sed 's/^.*BSD\.//'`
echo ${UNAME_MACHINE_ARCH}-unknown-libertybsd${UNAME_RELEASE}
exit ;;
*:ekkoBSD:*:*) *:ekkoBSD:*:*)
echo ${UNAME_MACHINE}-unknown-ekkobsd${UNAME_RELEASE} echo ${UNAME_MACHINE}-unknown-ekkobsd${UNAME_RELEASE}
exit ;; exit ;;
@@ -235,6 +256,9 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
*:MirBSD:*:*) *:MirBSD:*:*)
echo ${UNAME_MACHINE}-unknown-mirbsd${UNAME_RELEASE} echo ${UNAME_MACHINE}-unknown-mirbsd${UNAME_RELEASE}
exit ;; exit ;;
*:Sortix:*:*)
echo ${UNAME_MACHINE}-unknown-sortix
exit ;;
alpha:OSF1:*:*) alpha:OSF1:*:*)
case $UNAME_RELEASE in case $UNAME_RELEASE in
*4.0) *4.0)
@@ -251,42 +275,42 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^ The alpha \(.*\) processor.*$/\1/p' | head -n 1` ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^ The alpha \(.*\) processor.*$/\1/p' | head -n 1`
case "$ALPHA_CPU_TYPE" in case "$ALPHA_CPU_TYPE" in
"EV4 (21064)") "EV4 (21064)")
UNAME_MACHINE="alpha" ;; UNAME_MACHINE=alpha ;;
"EV4.5 (21064)") "EV4.5 (21064)")
UNAME_MACHINE="alpha" ;; UNAME_MACHINE=alpha ;;
"LCA4 (21066/21068)") "LCA4 (21066/21068)")
UNAME_MACHINE="alpha" ;; UNAME_MACHINE=alpha ;;
"EV5 (21164)") "EV5 (21164)")
UNAME_MACHINE="alphaev5" ;; UNAME_MACHINE=alphaev5 ;;
"EV5.6 (21164A)") "EV5.6 (21164A)")
UNAME_MACHINE="alphaev56" ;; UNAME_MACHINE=alphaev56 ;;
"EV5.6 (21164PC)") "EV5.6 (21164PC)")
UNAME_MACHINE="alphapca56" ;; UNAME_MACHINE=alphapca56 ;;
"EV5.7 (21164PC)") "EV5.7 (21164PC)")
UNAME_MACHINE="alphapca57" ;; UNAME_MACHINE=alphapca57 ;;
"EV6 (21264)") "EV6 (21264)")
UNAME_MACHINE="alphaev6" ;; UNAME_MACHINE=alphaev6 ;;
"EV6.7 (21264A)") "EV6.7 (21264A)")
UNAME_MACHINE="alphaev67" ;; UNAME_MACHINE=alphaev67 ;;
"EV6.8CB (21264C)") "EV6.8CB (21264C)")
UNAME_MACHINE="alphaev68" ;; UNAME_MACHINE=alphaev68 ;;
"EV6.8AL (21264B)") "EV6.8AL (21264B)")
UNAME_MACHINE="alphaev68" ;; UNAME_MACHINE=alphaev68 ;;
"EV6.8CX (21264D)") "EV6.8CX (21264D)")
UNAME_MACHINE="alphaev68" ;; UNAME_MACHINE=alphaev68 ;;
"EV6.9A (21264/EV69A)") "EV6.9A (21264/EV69A)")
UNAME_MACHINE="alphaev69" ;; UNAME_MACHINE=alphaev69 ;;
"EV7 (21364)") "EV7 (21364)")
UNAME_MACHINE="alphaev7" ;; UNAME_MACHINE=alphaev7 ;;
"EV7.9 (21364A)") "EV7.9 (21364A)")
UNAME_MACHINE="alphaev79" ;; UNAME_MACHINE=alphaev79 ;;
esac esac
# A Pn.n version is a patched version. # A Pn.n version is a patched version.
# A Vn.n version is a released version. # A Vn.n version is a released version.
# A Tn.n version is a released field test version. # A Tn.n version is a released field test version.
# A Xn.n version is an unreleased experimental baselevel. # A Xn.n version is an unreleased experimental baselevel.
# 1.2 uses "1.2" for uname -r. # 1.2 uses "1.2" for uname -r.
echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz`
# Reset EXIT trap before exiting to avoid spurious non-zero exit code. # Reset EXIT trap before exiting to avoid spurious non-zero exit code.
exitcode=$? exitcode=$?
trap '' 0 trap '' 0
@@ -359,16 +383,16 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
exit ;; exit ;;
i86pc:SunOS:5.*:* | i86xen:SunOS:5.*:*) i86pc:SunOS:5.*:* | i86xen:SunOS:5.*:*)
eval $set_cc_for_build eval $set_cc_for_build
SUN_ARCH="i386" SUN_ARCH=i386
# If there is a compiler, see if it is configured for 64-bit objects. # If there is a compiler, see if it is configured for 64-bit objects.
# Note that the Sun cc does not turn __LP64__ into 1 like gcc does. # Note that the Sun cc does not turn __LP64__ into 1 like gcc does.
# This test works for both compilers. # This test works for both compilers.
if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then if [ "$CC_FOR_BUILD" != no_compiler_found ]; then
if (echo '#ifdef __amd64'; echo IS_64BIT_ARCH; echo '#endif') | \ if (echo '#ifdef __amd64'; echo IS_64BIT_ARCH; echo '#endif') | \
(CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \ (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \
grep IS_64BIT_ARCH >/dev/null grep IS_64BIT_ARCH >/dev/null
then then
SUN_ARCH="x86_64" SUN_ARCH=x86_64
fi fi
fi fi
echo ${SUN_ARCH}-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` echo ${SUN_ARCH}-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
@@ -393,7 +417,7 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
exit ;; exit ;;
sun*:*:4.2BSD:*) sun*:*:4.2BSD:*)
UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null` UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null`
test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3 test "x${UNAME_RELEASE}" = x && UNAME_RELEASE=3
case "`/bin/arch`" in case "`/bin/arch`" in
sun3) sun3)
echo m68k-sun-sunos${UNAME_RELEASE} echo m68k-sun-sunos${UNAME_RELEASE}
@@ -579,8 +603,9 @@ EOF
else else
IBM_ARCH=powerpc IBM_ARCH=powerpc
fi fi
if [ -x /usr/bin/oslevel ] ; then if [ -x /usr/bin/lslpp ] ; then
IBM_REV=`/usr/bin/oslevel` IBM_REV=`/usr/bin/lslpp -Lqc bos.rte.libc |
awk -F: '{ print $3 }' | sed s/[0-9]*$/0/`
else else
IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE}
fi fi
@@ -617,13 +642,13 @@ EOF
sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null` sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null`
sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null` sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null`
case "${sc_cpu_version}" in case "${sc_cpu_version}" in
523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0 523) HP_ARCH=hppa1.0 ;; # CPU_PA_RISC1_0
528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1 528) HP_ARCH=hppa1.1 ;; # CPU_PA_RISC1_1
532) # CPU_PA_RISC2_0 532) # CPU_PA_RISC2_0
case "${sc_kernel_bits}" in case "${sc_kernel_bits}" in
32) HP_ARCH="hppa2.0n" ;; 32) HP_ARCH=hppa2.0n ;;
64) HP_ARCH="hppa2.0w" ;; 64) HP_ARCH=hppa2.0w ;;
'') HP_ARCH="hppa2.0" ;; # HP-UX 10.20 '') HP_ARCH=hppa2.0 ;; # HP-UX 10.20
esac ;; esac ;;
esac esac
fi fi
@@ -662,11 +687,11 @@ EOF
exit (0); exit (0);
} }
EOF EOF
(CCOPTS= $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy` (CCOPTS="" $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy`
test -z "$HP_ARCH" && HP_ARCH=hppa test -z "$HP_ARCH" && HP_ARCH=hppa
fi ;; fi ;;
esac esac
if [ ${HP_ARCH} = "hppa2.0w" ] if [ ${HP_ARCH} = hppa2.0w ]
then then
eval $set_cc_for_build eval $set_cc_for_build
@@ -679,12 +704,12 @@ EOF
# $ CC_FOR_BUILD="cc +DA2.0w" ./config.guess # $ CC_FOR_BUILD="cc +DA2.0w" ./config.guess
# => hppa64-hp-hpux11.23 # => hppa64-hp-hpux11.23
if echo __LP64__ | (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | if echo __LP64__ | (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) |
grep -q __LP64__ grep -q __LP64__
then then
HP_ARCH="hppa2.0w" HP_ARCH=hppa2.0w
else else
HP_ARCH="hppa64" HP_ARCH=hppa64
fi fi
fi fi
echo ${HP_ARCH}-hp-hpux${HPUX_REV} echo ${HP_ARCH}-hp-hpux${HPUX_REV}
@@ -789,14 +814,14 @@ EOF
echo craynv-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' echo craynv-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
exit ;; exit ;;
F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*) F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*)
FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` FUJITSU_PROC=`uname -m | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz`
FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` FUJITSU_SYS=`uname -p | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/\///'`
FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'` FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'`
echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
exit ;; exit ;;
5000:UNIX_System_V:4.*:*) 5000:UNIX_System_V:4.*:*)
FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` FUJITSU_SYS=`uname -p | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/\///'`
FUJITSU_REL=`echo ${UNAME_RELEASE} | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/ /_/'` FUJITSU_REL=`echo ${UNAME_RELEASE} | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/ /_/'`
echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
exit ;; exit ;;
i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*) i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*)
@@ -878,7 +903,7 @@ EOF
exit ;; exit ;;
*:GNU/*:*:*) *:GNU/*:*:*)
# other systems with GNU libc and userland # other systems with GNU libc and userland
echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr '[A-Z]' '[a-z]'``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-${LIBC} echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr "[:upper:]" "[:lower:]"``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-${LIBC}
exit ;; exit ;;
i*86:Minix:*:*) i*86:Minix:*:*)
echo ${UNAME_MACHINE}-pc-minix echo ${UNAME_MACHINE}-pc-minix
@@ -901,7 +926,7 @@ EOF
EV68*) UNAME_MACHINE=alphaev68 ;; EV68*) UNAME_MACHINE=alphaev68 ;;
esac esac
objdump --private-headers /bin/sh | grep -q ld.so.1 objdump --private-headers /bin/sh | grep -q ld.so.1
if test "$?" = 0 ; then LIBC="gnulibc1" ; fi if test "$?" = 0 ; then LIBC=gnulibc1 ; fi
echo ${UNAME_MACHINE}-unknown-linux-${LIBC} echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
exit ;; exit ;;
arc:Linux:*:* | arceb:Linux:*:*) arc:Linux:*:* | arceb:Linux:*:*)
@@ -932,6 +957,9 @@ EOF
crisv32:Linux:*:*) crisv32:Linux:*:*)
echo ${UNAME_MACHINE}-axis-linux-${LIBC} echo ${UNAME_MACHINE}-axis-linux-${LIBC}
exit ;; exit ;;
e2k:Linux:*:*)
echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
exit ;;
frv:Linux:*:*) frv:Linux:*:*)
echo ${UNAME_MACHINE}-unknown-linux-${LIBC} echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
exit ;; exit ;;
@@ -944,6 +972,9 @@ EOF
ia64:Linux:*:*) ia64:Linux:*:*)
echo ${UNAME_MACHINE}-unknown-linux-${LIBC} echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
exit ;; exit ;;
k1om:Linux:*:*)
echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
exit ;;
m32r*:Linux:*:*) m32r*:Linux:*:*)
echo ${UNAME_MACHINE}-unknown-linux-${LIBC} echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
exit ;; exit ;;
@@ -969,6 +1000,9 @@ EOF
eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^CPU'` eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^CPU'`
test x"${CPU}" != x && { echo "${CPU}-unknown-linux-${LIBC}"; exit; } test x"${CPU}" != x && { echo "${CPU}-unknown-linux-${LIBC}"; exit; }
;; ;;
mips64el:Linux:*:*)
echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
exit ;;
openrisc*:Linux:*:*) openrisc*:Linux:*:*)
echo or1k-unknown-linux-${LIBC} echo or1k-unknown-linux-${LIBC}
exit ;; exit ;;
@@ -1001,6 +1035,9 @@ EOF
ppcle:Linux:*:*) ppcle:Linux:*:*)
echo powerpcle-unknown-linux-${LIBC} echo powerpcle-unknown-linux-${LIBC}
exit ;; exit ;;
riscv32:Linux:*:* | riscv64:Linux:*:*)
echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
exit ;;
s390:Linux:*:* | s390x:Linux:*:*) s390:Linux:*:* | s390x:Linux:*:*)
echo ${UNAME_MACHINE}-ibm-linux-${LIBC} echo ${UNAME_MACHINE}-ibm-linux-${LIBC}
exit ;; exit ;;
@@ -1020,7 +1057,7 @@ EOF
echo ${UNAME_MACHINE}-dec-linux-${LIBC} echo ${UNAME_MACHINE}-dec-linux-${LIBC}
exit ;; exit ;;
x86_64:Linux:*:*) x86_64:Linux:*:*)
echo ${UNAME_MACHINE}-unknown-linux-${LIBC} echo ${UNAME_MACHINE}-pc-linux-${LIBC}
exit ;; exit ;;
xtensa*:Linux:*:*) xtensa*:Linux:*:*)
echo ${UNAME_MACHINE}-unknown-linux-${LIBC} echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
@@ -1099,7 +1136,7 @@ EOF
# uname -m prints for DJGPP always 'pc', but it prints nothing about # uname -m prints for DJGPP always 'pc', but it prints nothing about
# the processor, so we play safe by assuming i586. # the processor, so we play safe by assuming i586.
# Note: whatever this is, it MUST be the same as what config.sub # Note: whatever this is, it MUST be the same as what config.sub
# prints for the "djgpp" host, or else GDB configury will decide that # prints for the "djgpp" host, or else GDB configure will decide that
# this is a cross-build. # this is a cross-build.
echo i586-pc-msdosdjgpp echo i586-pc-msdosdjgpp
exit ;; exit ;;
@@ -1248,6 +1285,9 @@ EOF
SX-8R:SUPER-UX:*:*) SX-8R:SUPER-UX:*:*)
echo sx8r-nec-superux${UNAME_RELEASE} echo sx8r-nec-superux${UNAME_RELEASE}
exit ;; exit ;;
SX-ACE:SUPER-UX:*:*)
echo sxace-nec-superux${UNAME_RELEASE}
exit ;;
Power*:Rhapsody:*:*) Power*:Rhapsody:*:*)
echo powerpc-apple-rhapsody${UNAME_RELEASE} echo powerpc-apple-rhapsody${UNAME_RELEASE}
exit ;; exit ;;
@@ -1261,9 +1301,9 @@ EOF
UNAME_PROCESSOR=powerpc UNAME_PROCESSOR=powerpc
fi fi
if test `echo "$UNAME_RELEASE" | sed -e 's/\..*//'` -le 10 ; then if test `echo "$UNAME_RELEASE" | sed -e 's/\..*//'` -le 10 ; then
if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then if [ "$CC_FOR_BUILD" != no_compiler_found ]; then
if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \ if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \
(CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \ (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \
grep IS_64BIT_ARCH >/dev/null grep IS_64BIT_ARCH >/dev/null
then then
case $UNAME_PROCESSOR in case $UNAME_PROCESSOR in
@@ -1285,7 +1325,7 @@ EOF
exit ;; exit ;;
*:procnto*:*:* | *:QNX:[0123456789]*:*) *:procnto*:*:* | *:QNX:[0123456789]*:*)
UNAME_PROCESSOR=`uname -p` UNAME_PROCESSOR=`uname -p`
if test "$UNAME_PROCESSOR" = "x86"; then if test "$UNAME_PROCESSOR" = x86; then
UNAME_PROCESSOR=i386 UNAME_PROCESSOR=i386
UNAME_MACHINE=pc UNAME_MACHINE=pc
fi fi
@@ -1316,7 +1356,7 @@ EOF
# "uname -m" is not consistent, so use $cputype instead. 386 # "uname -m" is not consistent, so use $cputype instead. 386
# is converted to i386 for consistency with other x86 # is converted to i386 for consistency with other x86
# operating systems. # operating systems.
if test "$cputype" = "386"; then if test "$cputype" = 386; then
UNAME_MACHINE=i386 UNAME_MACHINE=i386
else else
UNAME_MACHINE="$cputype" UNAME_MACHINE="$cputype"
@@ -1358,7 +1398,7 @@ EOF
echo i386-pc-xenix echo i386-pc-xenix
exit ;; exit ;;
i*86:skyos:*:*) i*86:skyos:*:*)
echo ${UNAME_MACHINE}-pc-skyos`echo ${UNAME_RELEASE}` | sed -e 's/ .*$//' echo ${UNAME_MACHINE}-pc-skyos`echo ${UNAME_RELEASE} | sed -e 's/ .*$//'`
exit ;; exit ;;
i*86:rdos:*:*) i*86:rdos:*:*)
echo ${UNAME_MACHINE}-pc-rdos echo ${UNAME_MACHINE}-pc-rdos
@@ -1369,23 +1409,25 @@ EOF
x86_64:VMkernel:*:*) x86_64:VMkernel:*:*)
echo ${UNAME_MACHINE}-unknown-esx echo ${UNAME_MACHINE}-unknown-esx
exit ;; exit ;;
amd64:Isilon\ OneFS:*:*)
echo x86_64-unknown-onefs
exit ;;
esac esac
cat >&2 <<EOF cat >&2 <<EOF
$0: unable to guess system type $0: unable to guess system type
This script, last modified $timestamp, has failed to recognize This script (version $timestamp), has failed to recognize the
the operating system you are using. It is advised that you operating system you are using. If your script is old, overwrite
download the most up to date version of the config scripts from config.guess and config.sub with the latest versions from:
http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess
and and
http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub;hb=HEAD http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub
If the version you run ($0) is already up to date, please If $0 has already been updated, send the following data and any
send the following data and any information you think might be information you think might be pertinent to config-patches@gnu.org to
pertinent to <config-patches@gnu.org> in order to provide the needed provide the necessary information to handle your system.
information to handle your system.
config.guess timestamp = $timestamp config.guess timestamp = $timestamp

76
build-aux/config.sub vendored
View File

@@ -1,8 +1,8 @@
#! /bin/sh #! /bin/sh
# Configuration validation subroutine script. # Configuration validation subroutine script.
# Copyright 1992-2014 Free Software Foundation, Inc. # Copyright 1992-2016 Free Software Foundation, Inc.
timestamp='2014-05-01' timestamp='2016-11-04'
# This file is free software; you can redistribute it and/or modify it # This file is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by # under the terms of the GNU General Public License as published by
@@ -25,7 +25,7 @@ timestamp='2014-05-01'
# of the GNU General Public License, version 3 ("GPLv3"). # of the GNU General Public License, version 3 ("GPLv3").
# Please send patches with a ChangeLog entry to config-patches@gnu.org. # Please send patches to <config-patches@gnu.org>.
# #
# Configuration subroutine to validate and canonicalize a configuration type. # Configuration subroutine to validate and canonicalize a configuration type.
# Supply the specified configuration type as an argument. # Supply the specified configuration type as an argument.
@@ -33,7 +33,7 @@ timestamp='2014-05-01'
# Otherwise, we print the canonical config type on stdout and succeed. # Otherwise, we print the canonical config type on stdout and succeed.
# You can get the latest version of this script from: # You can get the latest version of this script from:
# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub;hb=HEAD # http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub
# This file is supposed to be the same for all GNU packages # This file is supposed to be the same for all GNU packages
# and recognize all the CPU types, system types and aliases # and recognize all the CPU types, system types and aliases
@@ -53,8 +53,7 @@ timestamp='2014-05-01'
me=`echo "$0" | sed -e 's,.*/,,'` me=`echo "$0" | sed -e 's,.*/,,'`
usage="\ usage="\
Usage: $0 [OPTION] CPU-MFR-OPSYS Usage: $0 [OPTION] CPU-MFR-OPSYS or ALIAS
$0 [OPTION] ALIAS
Canonicalize a configuration name. Canonicalize a configuration name.
@@ -68,7 +67,7 @@ Report bugs and patches to <config-patches@gnu.org>."
version="\ version="\
GNU config.sub ($timestamp) GNU config.sub ($timestamp)
Copyright 1992-2014 Free Software Foundation, Inc. Copyright 1992-2016 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
@@ -117,8 +116,8 @@ maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'`
case $maybe_os in case $maybe_os in
nto-qnx* | linux-gnu* | linux-android* | linux-dietlibc | linux-newlib* | \ nto-qnx* | linux-gnu* | linux-android* | linux-dietlibc | linux-newlib* | \
linux-musl* | linux-uclibc* | uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | \ linux-musl* | linux-uclibc* | uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | \
knetbsd*-gnu* | netbsd*-gnu* | \ knetbsd*-gnu* | netbsd*-gnu* | netbsd*-eabi* | \
kopensolaris*-gnu* | \ kopensolaris*-gnu* | cloudabi*-eabi* | \
storm-chaos* | os2-emx* | rtmk-nova*) storm-chaos* | os2-emx* | rtmk-nova*)
os=-$maybe_os os=-$maybe_os
basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'` basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`
@@ -255,12 +254,13 @@ case $basic_machine in
| arc | arceb \ | arc | arceb \
| arm | arm[bl]e | arme[lb] | armv[2-8] | armv[3-8][lb] | armv7[arm] \ | arm | arm[bl]e | arme[lb] | armv[2-8] | armv[3-8][lb] | armv7[arm] \
| avr | avr32 \ | avr | avr32 \
| ba \
| be32 | be64 \ | be32 | be64 \
| bfin \ | bfin \
| c4x | c8051 | clipper \ | c4x | c8051 | clipper \
| d10v | d30v | dlx | dsp16xx \ | d10v | d30v | dlx | dsp16xx \
| epiphany \ | e2k | epiphany \
| fido | fr30 | frv \ | fido | fr30 | frv | ft32 \
| h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \ | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \
| hexagon \ | hexagon \
| i370 | i860 | i960 | ia64 \ | i370 | i860 | i960 | ia64 \
@@ -301,10 +301,12 @@ case $basic_machine in
| open8 | or1k | or1knd | or32 \ | open8 | or1k | or1knd | or32 \
| pdp10 | pdp11 | pj | pjl \ | pdp10 | pdp11 | pj | pjl \
| powerpc | powerpc64 | powerpc64le | powerpcle \ | powerpc | powerpc64 | powerpc64le | powerpcle \
| pru \
| pyramid \ | pyramid \
| riscv32 | riscv64 \
| rl78 | rx \ | rl78 | rx \
| score \ | score \
| sh | sh[1234] | sh[24]a | sh[24]aeb | sh[23]e | sh[34]eb | sheb | shbe | shle | sh[1234]le | sh3ele \ | sh | sh[1234] | sh[24]a | sh[24]aeb | sh[23]e | sh[234]eb | sheb | shbe | shle | sh[1234]le | sh3ele \
| sh64 | sh64le \ | sh64 | sh64le \
| sparc | sparc64 | sparc64b | sparc64v | sparc86x | sparclet | sparclite \ | sparc | sparc64 | sparc64b | sparc64v | sparc86x | sparclet | sparclite \
| sparcv8 | sparcv9 | sparcv9b | sparcv9v \ | sparcv8 | sparcv9 | sparcv9b | sparcv9v \
@@ -312,6 +314,7 @@ case $basic_machine in
| tahoe | tic4x | tic54x | tic55x | tic6x | tic80 | tron \ | tahoe | tic4x | tic54x | tic55x | tic6x | tic80 | tron \
| ubicom32 \ | ubicom32 \
| v850 | v850e | v850e1 | v850e2 | v850es | v850e2v3 \ | v850 | v850e | v850e1 | v850e2 | v850es | v850e2v3 \
| visium \
| we32k \ | we32k \
| x86 | xc16x | xstormy16 | xtensa \ | x86 | xc16x | xstormy16 | xtensa \
| z8k | z80) | z8k | z80)
@@ -326,6 +329,9 @@ case $basic_machine in
c6x) c6x)
basic_machine=tic6x-unknown basic_machine=tic6x-unknown
;; ;;
leon|leon[3-9])
basic_machine=sparc-$basic_machine
;;
m6811 | m68hc11 | m6812 | m68hc12 | m68hcs12x | nvptx | picochip) m6811 | m68hc11 | m6812 | m68hc12 | m68hcs12x | nvptx | picochip)
basic_machine=$basic_machine-unknown basic_machine=$basic_machine-unknown
os=-none os=-none
@@ -371,12 +377,13 @@ case $basic_machine in
| alphapca5[67]-* | alpha64pca5[67]-* | arc-* | arceb-* \ | alphapca5[67]-* | alpha64pca5[67]-* | arc-* | arceb-* \
| arm-* | armbe-* | armle-* | armeb-* | armv*-* \ | arm-* | armbe-* | armle-* | armeb-* | armv*-* \
| avr-* | avr32-* \ | avr-* | avr32-* \
| ba-* \
| be32-* | be64-* \ | be32-* | be64-* \
| bfin-* | bs2000-* \ | bfin-* | bs2000-* \
| c[123]* | c30-* | [cjt]90-* | c4x-* \ | c[123]* | c30-* | [cjt]90-* | c4x-* \
| c8051-* | clipper-* | craynv-* | cydra-* \ | c8051-* | clipper-* | craynv-* | cydra-* \
| d10v-* | d30v-* | dlx-* \ | d10v-* | d30v-* | dlx-* \
| elxsi-* \ | e2k-* | elxsi-* \
| f30[01]-* | f700-* | fido-* | fr30-* | frv-* | fx80-* \ | f30[01]-* | f700-* | fido-* | fr30-* | frv-* | fx80-* \
| h8300-* | h8500-* \ | h8300-* | h8500-* \
| hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \ | hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \
@@ -422,13 +429,15 @@ case $basic_machine in
| orion-* \ | orion-* \
| pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \ | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \
| powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* \ | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* \
| pru-* \
| pyramid-* \ | pyramid-* \
| riscv32-* | riscv64-* \
| rl78-* | romp-* | rs6000-* | rx-* \ | rl78-* | romp-* | rs6000-* | rx-* \
| sh-* | sh[1234]-* | sh[24]a-* | sh[24]aeb-* | sh[23]e-* | sh[34]eb-* | sheb-* | shbe-* \ | sh-* | sh[1234]-* | sh[24]a-* | sh[24]aeb-* | sh[23]e-* | sh[34]eb-* | sheb-* | shbe-* \
| shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \ | shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \
| sparc-* | sparc64-* | sparc64b-* | sparc64v-* | sparc86x-* | sparclet-* \ | sparc-* | sparc64-* | sparc64b-* | sparc64v-* | sparc86x-* | sparclet-* \
| sparclite-* \ | sparclite-* \
| sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | sv1-* | sx?-* \ | sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | sv1-* | sx*-* \
| tahoe-* \ | tahoe-* \
| tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \ | tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \
| tile*-* \ | tile*-* \
@@ -436,6 +445,7 @@ case $basic_machine in
| ubicom32-* \ | ubicom32-* \
| v850-* | v850e-* | v850e1-* | v850es-* | v850e2-* | v850e2v3-* \ | v850-* | v850e-* | v850e1-* | v850es-* | v850e2-* | v850e2v3-* \
| vax-* \ | vax-* \
| visium-* \
| we32k-* \ | we32k-* \
| x86-* | x86_64-* | xc16x-* | xps100-* \ | x86-* | x86_64-* | xc16x-* | xps100-* \
| xstormy16-* | xtensa*-* \ | xstormy16-* | xtensa*-* \
@@ -512,6 +522,9 @@ case $basic_machine in
basic_machine=i386-pc basic_machine=i386-pc
os=-aros os=-aros
;; ;;
asmjs)
basic_machine=asmjs-unknown
;;
aux) aux)
basic_machine=m68k-apple basic_machine=m68k-apple
os=-aux os=-aux
@@ -632,6 +645,14 @@ case $basic_machine in
basic_machine=m68k-bull basic_machine=m68k-bull
os=-sysv3 os=-sysv3
;; ;;
e500v[12])
basic_machine=powerpc-unknown
os=$os"spe"
;;
e500v[12]-*)
basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'`
os=$os"spe"
;;
ebmon29k) ebmon29k)
basic_machine=a29k-amd basic_machine=a29k-amd
os=-ebmon os=-ebmon
@@ -773,6 +794,9 @@ case $basic_machine in
basic_machine=m68k-isi basic_machine=m68k-isi
os=-sysv os=-sysv
;; ;;
leon-*|leon[3-9]-*)
basic_machine=sparc-`echo $basic_machine | sed 's/-.*//'`
;;
m68knommu) m68knommu)
basic_machine=m68k-unknown basic_machine=m68k-unknown
os=-linux os=-linux
@@ -828,6 +852,10 @@ case $basic_machine in
basic_machine=powerpc-unknown basic_machine=powerpc-unknown
os=-morphos os=-morphos
;; ;;
moxiebox)
basic_machine=moxie-unknown
os=-moxiebox
;;
msdos) msdos)
basic_machine=i386-pc basic_machine=i386-pc
os=-msdos os=-msdos
@@ -1004,7 +1032,7 @@ case $basic_machine in
ppc-* | ppcbe-*) ppc-* | ppcbe-*)
basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'` basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'`
;; ;;
ppcle | powerpclittle | ppc-le | powerpc-little) ppcle | powerpclittle)
basic_machine=powerpcle-unknown basic_machine=powerpcle-unknown
;; ;;
ppcle-* | powerpclittle-*) ppcle-* | powerpclittle-*)
@@ -1014,7 +1042,7 @@ case $basic_machine in
;; ;;
ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'` ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'`
;; ;;
ppc64le | powerpc64little | ppc64-le | powerpc64-little) ppc64le | powerpc64little)
basic_machine=powerpc64le-unknown basic_machine=powerpc64le-unknown
;; ;;
ppc64le-* | powerpc64little-*) ppc64le-* | powerpc64little-*)
@@ -1360,27 +1388,28 @@ case $os in
| -hpux* | -unos* | -osf* | -luna* | -dgux* | -auroraux* | -solaris* \ | -hpux* | -unos* | -osf* | -luna* | -dgux* | -auroraux* | -solaris* \
| -sym* | -kopensolaris* | -plan9* \ | -sym* | -kopensolaris* | -plan9* \
| -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \ | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \
| -aos* | -aros* \ | -aos* | -aros* | -cloudabi* | -sortix* \
| -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \ | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \
| -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \ | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \
| -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \ | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \
| -bitrig* | -openbsd* | -solidbsd* \ | -bitrig* | -openbsd* | -solidbsd* | -libertybsd* \
| -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \ | -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \
| -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \ | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \
| -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \ | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \
| -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \ | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \
| -chorusos* | -chorusrdb* | -cegcc* \ | -chorusos* | -chorusrdb* | -cegcc* \
| -cygwin* | -msys* | -pe* | -psos* | -moss* | -proelf* | -rtems* \ | -cygwin* | -msys* | -pe* | -psos* | -moss* | -proelf* | -rtems* \
| -mingw32* | -mingw64* | -linux-gnu* | -linux-android* \ | -midipix* | -mingw32* | -mingw64* | -linux-gnu* | -linux-android* \
| -linux-newlib* | -linux-musl* | -linux-uclibc* \ | -linux-newlib* | -linux-musl* | -linux-uclibc* \
| -uxpv* | -beos* | -mpeix* | -udk* \ | -uxpv* | -beos* | -mpeix* | -udk* | -moxiebox* \
| -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \ | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \
| -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \ | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \
| -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \ | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \
| -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \ | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \
| -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \ | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \
| -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \ | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \
| -skyos* | -haiku* | -rdos* | -toppers* | -drops* | -es* | -tirtos*) | -skyos* | -haiku* | -rdos* | -toppers* | -drops* | -es* \
| -onefs* | -tirtos* | -phoenix* | -fuchsia*)
# Remember, each alternative MUST END IN *, to match a version number. # Remember, each alternative MUST END IN *, to match a version number.
;; ;;
-qnx*) -qnx*)
@@ -1404,9 +1433,6 @@ case $os in
-mac*) -mac*)
os=`echo $os | sed -e 's|mac|macos|'` os=`echo $os | sed -e 's|mac|macos|'`
;; ;;
# Apple iOS
-ios*)
;;
-linux-dietlibc) -linux-dietlibc)
os=-linux-dietlibc os=-linux-dietlibc
;; ;;
@@ -1515,6 +1541,8 @@ case $os in
;; ;;
-nacl*) -nacl*)
;; ;;
-ios)
;;
-none) -none)
;; ;;
*) *)

View File

@@ -6,29 +6,66 @@ AC_CONFIG_AUX_DIR([build-aux])
dnl ============================================================================ dnl ============================================================================
dnl Custom macro definitions. dnl Custom macro definitions.
dnl JE_CFLAGS_APPEND(cflag) dnl JE_CONCAT_VVV(r, a, b)
AC_DEFUN([JE_CFLAGS_APPEND], dnl
dnl Set $r to the concatenation of $a and $b, with a space separating them iff
dnl both $a and $b are non-emty.
AC_DEFUN([JE_CONCAT_VVV],
if test "x[$]{$2}" = "x" -o "x[$]{$3}" = "x" ; then
$1="[$]{$2}[$]{$3}"
else
$1="[$]{$2} [$]{$3}"
fi
)
dnl JE_APPEND_VS(a, b)
dnl
dnl Set $a to the concatenation of $a and b, with a space separating them iff
dnl both $a and b are non-empty.
AC_DEFUN([JE_APPEND_VS],
T_APPEND_V=$2
JE_CONCAT_VVV($1, $1, T_APPEND_V)
)
CONFIGURE_CFLAGS=
SPECIFIED_CFLAGS="${CFLAGS}"
dnl JE_CFLAGS_ADD(cflag)
dnl
dnl CFLAGS is the concatenation of CONFIGURE_CFLAGS and SPECIFIED_CFLAGS
dnl (ignoring EXTRA_CFLAGS, which does not impact configure tests. This macro
dnl appends to CONFIGURE_CFLAGS and regenerates CFLAGS.
AC_DEFUN([JE_CFLAGS_ADD],
[ [
AC_MSG_CHECKING([whether compiler supports $1]) AC_MSG_CHECKING([whether compiler supports $1])
TCFLAGS="${CFLAGS}" T_CONFIGURE_CFLAGS="${CONFIGURE_CFLAGS}"
if test "x${CFLAGS}" = "x" ; then JE_APPEND_VS(CONFIGURE_CFLAGS, $1)
CFLAGS="$1" JE_CONCAT_VVV(CFLAGS, CONFIGURE_CFLAGS, SPECIFIED_CFLAGS)
else
CFLAGS="${CFLAGS} $1"
fi
AC_COMPILE_IFELSE([AC_LANG_PROGRAM( AC_COMPILE_IFELSE([AC_LANG_PROGRAM(
[[ [[
]], [[ ]], [[
return 0; return 0;
]])], ]])],
[je_cv_cflags_appended=$1] [je_cv_cflags_added=$1]
AC_MSG_RESULT([yes]), AC_MSG_RESULT([yes]),
[je_cv_cflags_appended=] [je_cv_cflags_added=]
AC_MSG_RESULT([no]) AC_MSG_RESULT([no])
[CFLAGS="${TCFLAGS}"] [CONFIGURE_CFLAGS="${T_CONFIGURE_CFLAGS}"]
) )
JE_CONCAT_VVV(CFLAGS, CONFIGURE_CFLAGS, SPECIFIED_CFLAGS)
]) ])
dnl JE_CFLAGS_SAVE()
dnl JE_CFLAGS_RESTORE()
dnl
dnl Save/restore CFLAGS. Nesting is not supported.
AC_DEFUN([JE_CFLAGS_SAVE],
SAVED_CONFIGURE_CFLAGS="${CONFIGURE_CFLAGS}"
)
AC_DEFUN([JE_CFLAGS_RESTORE],
CONFIGURE_CFLAGS="${SAVED_CONFIGURE_CFLAGS}"
JE_CONCAT_VVV(CFLAGS, CONFIGURE_CFLAGS, SPECIFIED_CFLAGS)
)
dnl JE_COMPILABLE(label, hcode, mcode, rvar) dnl JE_COMPILABLE(label, hcode, mcode, rvar)
dnl dnl
dnl Use AC_LINK_IFELSE() rather than AC_COMPILE_IFELSE() so that linker errors dnl Use AC_LINK_IFELSE() rather than AC_COMPILE_IFELSE() so that linker errors
@@ -118,6 +155,7 @@ dnl If CFLAGS isn't defined, set CFLAGS to something reasonable. Otherwise,
dnl just prevent autoconf from molesting CFLAGS. dnl just prevent autoconf from molesting CFLAGS.
CFLAGS=$CFLAGS CFLAGS=$CFLAGS
AC_PROG_CC AC_PROG_CC
if test "x$GCC" != "xyes" ; then if test "x$GCC" != "xyes" ; then
AC_CACHE_CHECK([whether compiler is MSVC], AC_CACHE_CHECK([whether compiler is MSVC],
[je_cv_msvc], [je_cv_msvc],
@@ -131,32 +169,82 @@ if test "x$GCC" != "xyes" ; then
[je_cv_msvc=no])]) [je_cv_msvc=no])])
fi fi
if test "x$CFLAGS" = "x" ; then dnl check if a cray prgenv wrapper compiler is being used
no_CFLAGS="yes" je_cv_cray_prgenv_wrapper=""
if test "x$GCC" = "xyes" ; then if test "x${PE_ENV}" != "x" ; then
JE_CFLAGS_APPEND([-std=gnu99]) case "${CC}" in
if test "x$je_cv_cflags_appended" = "x-std=gnu99" ; then CC|cc)
je_cv_cray_prgenv_wrapper="yes"
;;
*)
;;
esac
fi
AC_CACHE_CHECK([whether compiler is cray],
[je_cv_cray],
[AC_COMPILE_IFELSE([AC_LANG_PROGRAM([],
[
#ifndef _CRAYC
int fail[-1];
#endif
])],
[je_cv_cray=yes],
[je_cv_cray=no])])
if test "x${je_cv_cray}" = "xyes" ; then
AC_CACHE_CHECK([whether cray compiler version is 8.4],
[je_cv_cray_84],
[AC_COMPILE_IFELSE([AC_LANG_PROGRAM([],
[
#if !(_RELEASE_MAJOR == 8 && _RELEASE_MINOR == 4)
int fail[-1];
#endif
])],
[je_cv_cray_84=yes],
[je_cv_cray_84=no])])
fi
if test "x$GCC" = "xyes" ; then
JE_CFLAGS_ADD([-std=gnu11])
if test "x$je_cv_cflags_added" = "x-std=gnu11" ; then
AC_DEFINE_UNQUOTED([JEMALLOC_HAS_RESTRICT])
else
JE_CFLAGS_ADD([-std=gnu99])
if test "x$je_cv_cflags_added" = "x-std=gnu99" ; then
AC_DEFINE_UNQUOTED([JEMALLOC_HAS_RESTRICT]) AC_DEFINE_UNQUOTED([JEMALLOC_HAS_RESTRICT])
fi fi
JE_CFLAGS_APPEND([-Wall]) fi
JE_CFLAGS_APPEND([-Werror=declaration-after-statement]) JE_CFLAGS_ADD([-Wall])
JE_CFLAGS_APPEND([-Wshorten-64-to-32]) JE_CFLAGS_ADD([-Werror=declaration-after-statement])
JE_CFLAGS_APPEND([-Wsign-compare]) JE_CFLAGS_ADD([-Wshorten-64-to-32])
JE_CFLAGS_APPEND([-pipe]) JE_CFLAGS_ADD([-Wsign-compare])
JE_CFLAGS_APPEND([-g3]) JE_CFLAGS_ADD([-pipe])
elif test "x$je_cv_msvc" = "xyes" ; then JE_CFLAGS_ADD([-g3])
CC="$CC -nologo" elif test "x$je_cv_msvc" = "xyes" ; then
JE_CFLAGS_APPEND([-Zi]) CC="$CC -nologo"
JE_CFLAGS_APPEND([-MT]) JE_CFLAGS_ADD([-Zi])
JE_CFLAGS_APPEND([-W3]) JE_CFLAGS_ADD([-MT])
JE_CFLAGS_APPEND([-FS]) JE_CFLAGS_ADD([-W3])
CPPFLAGS="$CPPFLAGS -I${srcdir}/include/msvc_compat" JE_CFLAGS_ADD([-FS])
JE_APPEND_VS(CPPFLAGS, -I${srcdir}/include/msvc_compat)
fi
if test "x$je_cv_cray" = "xyes" ; then
dnl cray compiler 8.4 has an inlining bug
if test "x$je_cv_cray_84" = "xyes" ; then
JE_CFLAGS_ADD([-hipa2])
JE_CFLAGS_ADD([-hnognu])
fi
if test "x$enable_cc_silence" != "xno" ; then
dnl ignore unreachable code warning
JE_CFLAGS_ADD([-hnomessage=128])
dnl ignore redefinition of "malloc", "free", etc warning
JE_CFLAGS_ADD([-hnomessage=1357])
fi fi
fi fi
dnl Append EXTRA_CFLAGS to CFLAGS, if defined. AC_SUBST([CONFIGURE_CFLAGS])
if test "x$EXTRA_CFLAGS" != "x" ; then AC_SUBST([SPECIFIED_CFLAGS])
JE_CFLAGS_APPEND([$EXTRA_CFLAGS]) AC_SUBST([EXTRA_CFLAGS])
fi
AC_PROG_CPP AC_PROG_CPP
AC_C_BIGENDIAN([ac_cv_big_endian=1], [ac_cv_big_endian=0]) AC_C_BIGENDIAN([ac_cv_big_endian=1], [ac_cv_big_endian=0])
@@ -165,7 +253,7 @@ if test "x${ac_cv_big_endian}" = "x1" ; then
fi fi
if test "x${je_cv_msvc}" = "xyes" -a "x${ac_cv_header_inttypes_h}" = "xno"; then if test "x${je_cv_msvc}" = "xyes" -a "x${ac_cv_header_inttypes_h}" = "xno"; then
CPPFLAGS="$CPPFLAGS -I${srcdir}/include/msvc_compat/C99" JE_APPEND_VS(CPPFLAGS, -I${srcdir}/include/msvc_compat/C99)
fi fi
if test "x${je_cv_msvc}" = "xyes" ; then if test "x${je_cv_msvc}" = "xyes" ; then
@@ -263,17 +351,27 @@ o="$ac_objext"
a="a" a="a"
exe="$ac_exeext" exe="$ac_exeext"
libprefix="lib" libprefix="lib"
link_whole_archive="0"
DSO_LDFLAGS='-shared -Wl,-soname,$(@F)' DSO_LDFLAGS='-shared -Wl,-soname,$(@F)'
RPATH='-Wl,-rpath,$(1)' RPATH='-Wl,-rpath,$(1)'
SOREV="${so}.${rev}" SOREV="${so}.${rev}"
PIC_CFLAGS='-fPIC -DPIC' PIC_CFLAGS='-fPIC -DPIC'
CTARGET='-o $@' CTARGET='-o $@'
LDTARGET='-o $@' LDTARGET='-o $@'
TEST_LD_MODE=
EXTRA_LDFLAGS= EXTRA_LDFLAGS=
ARFLAGS='crus' ARFLAGS='crus'
AROUT=' $@' AROUT=' $@'
CC_MM=1 CC_MM=1
if test "x$je_cv_cray_prgenv_wrapper" = "xyes" ; then
TEST_LD_MODE='-dynamic'
fi
if test "x${je_cv_cray}" = "xyes" ; then
CC_MM=
fi
AN_MAKEVAR([AR], [AC_PROG_AR]) AN_MAKEVAR([AR], [AC_PROG_AR])
AN_PROGRAM([ar], [AC_PROG_AR]) AN_PROGRAM([ar], [AC_PROG_AR])
AC_DEFUN([AC_PROG_AR], [AC_CHECK_TOOL(AR, ar, :)]) AC_DEFUN([AC_PROG_AR], [AC_CHECK_TOOL(AR, ar, :)])
@@ -290,9 +388,7 @@ default_munmap="1"
maps_coalesce="1" maps_coalesce="1"
case "${host}" in case "${host}" in
*-*-darwin* | *-*-ios*) *-*-darwin* | *-*-ios*)
CFLAGS="$CFLAGS"
abi="macho" abi="macho"
AC_DEFINE([JEMALLOC_PURGE_MADVISE_FREE], [ ])
RPATH="" RPATH=""
LD_PRELOAD_VAR="DYLD_INSERT_LIBRARIES" LD_PRELOAD_VAR="DYLD_INSERT_LIBRARIES"
so="dylib" so="dylib"
@@ -303,35 +399,37 @@ case "${host}" in
sbrk_deprecated="1" sbrk_deprecated="1"
;; ;;
*-*-freebsd*) *-*-freebsd*)
CFLAGS="$CFLAGS"
abi="elf" abi="elf"
AC_DEFINE([JEMALLOC_SYSCTL_VM_OVERCOMMIT], [ ]) AC_DEFINE([JEMALLOC_SYSCTL_VM_OVERCOMMIT], [ ])
AC_DEFINE([JEMALLOC_PURGE_MADVISE_FREE], [ ])
force_lazy_lock="1" force_lazy_lock="1"
;; ;;
*-*-dragonfly*) *-*-dragonfly*)
CFLAGS="$CFLAGS"
abi="elf" abi="elf"
AC_DEFINE([JEMALLOC_PURGE_MADVISE_FREE], [ ])
;; ;;
*-*-openbsd*) *-*-openbsd*)
CFLAGS="$CFLAGS"
abi="elf" abi="elf"
AC_DEFINE([JEMALLOC_PURGE_MADVISE_FREE], [ ])
force_tls="0" force_tls="0"
;; ;;
*-*-bitrig*) *-*-bitrig*)
CFLAGS="$CFLAGS"
abi="elf" abi="elf"
AC_DEFINE([JEMALLOC_PURGE_MADVISE_FREE], [ ])
;; ;;
*-*-linux*) *-*-linux-android)
CFLAGS="$CFLAGS" dnl syscall(2) and secure_getenv(3) are exposed by _GNU_SOURCE.
CPPFLAGS="$CPPFLAGS -D_GNU_SOURCE" JE_APPEND_VS(CPPFLAGS, -D_GNU_SOURCE)
abi="elf"
AC_DEFINE([JEMALLOC_HAS_ALLOCA_H])
AC_DEFINE([JEMALLOC_PROC_SYS_VM_OVERCOMMIT_MEMORY], [ ])
AC_DEFINE([JEMALLOC_THREADED_INIT], [ ])
AC_DEFINE([JEMALLOC_C11ATOMICS])
force_tls="0"
default_munmap="0"
;;
*-*-linux* | *-*-kfreebsd*)
dnl syscall(2) and secure_getenv(3) are exposed by _GNU_SOURCE.
JE_APPEND_VS(CPPFLAGS, -D_GNU_SOURCE)
abi="elf" abi="elf"
AC_DEFINE([JEMALLOC_HAS_ALLOCA_H]) AC_DEFINE([JEMALLOC_HAS_ALLOCA_H])
AC_DEFINE([JEMALLOC_PROC_SYS_VM_OVERCOMMIT_MEMORY], [ ]) AC_DEFINE([JEMALLOC_PROC_SYS_VM_OVERCOMMIT_MEMORY], [ ])
AC_DEFINE([JEMALLOC_PURGE_MADVISE_DONTNEED], [ ])
AC_DEFINE([JEMALLOC_THREADED_INIT], [ ]) AC_DEFINE([JEMALLOC_THREADED_INIT], [ ])
AC_DEFINE([JEMALLOC_USE_CXX_THROW], [ ]) AC_DEFINE([JEMALLOC_USE_CXX_THROW], [ ])
default_munmap="0" default_munmap="0"
@@ -345,19 +443,16 @@ case "${host}" in
#error aout #error aout
#endif #endif
]])], ]])],
[CFLAGS="$CFLAGS"; abi="elf"], [abi="elf"],
[abi="aout"]) [abi="aout"])
AC_MSG_RESULT([$abi]) AC_MSG_RESULT([$abi])
AC_DEFINE([JEMALLOC_PURGE_MADVISE_FREE], [ ])
;; ;;
*-*-solaris2*) *-*-solaris2*)
CFLAGS="$CFLAGS"
abi="elf" abi="elf"
AC_DEFINE([JEMALLOC_PURGE_MADVISE_FREE], [ ])
RPATH='-Wl,-R,$(1)' RPATH='-Wl,-R,$(1)'
dnl Solaris needs this for sigwait(). dnl Solaris needs this for sigwait().
CPPFLAGS="$CPPFLAGS -D_POSIX_PTHREAD_SEMANTICS" JE_APPEND_VS(CPPFLAGS, -D_POSIX_PTHREAD_SEMANTICS)
LIBS="$LIBS -lposix4 -lsocket -lnsl" JE_APPEND_VS(LIBS, -lposix4 -lsocket -lnsl)
;; ;;
*-ibm-aix*) *-ibm-aix*)
if "$LG_SIZEOF_PTR" = "8"; then if "$LG_SIZEOF_PTR" = "8"; then
@@ -372,7 +467,6 @@ case "${host}" in
*-*-mingw* | *-*-cygwin*) *-*-mingw* | *-*-cygwin*)
abi="pecoff" abi="pecoff"
force_tls="0" force_tls="0"
force_lazy_lock="1"
maps_coalesce="0" maps_coalesce="0"
RPATH="" RPATH=""
so="dll" so="dll"
@@ -389,6 +483,7 @@ case "${host}" in
else else
importlib="${so}" importlib="${so}"
DSO_LDFLAGS="-shared" DSO_LDFLAGS="-shared"
link_whole_archive="1"
fi fi
a="lib" a="lib"
libprefix="" libprefix=""
@@ -426,17 +521,28 @@ AC_SUBST([o])
AC_SUBST([a]) AC_SUBST([a])
AC_SUBST([exe]) AC_SUBST([exe])
AC_SUBST([libprefix]) AC_SUBST([libprefix])
AC_SUBST([link_whole_archive])
AC_SUBST([DSO_LDFLAGS]) AC_SUBST([DSO_LDFLAGS])
AC_SUBST([EXTRA_LDFLAGS]) AC_SUBST([EXTRA_LDFLAGS])
AC_SUBST([SOREV]) AC_SUBST([SOREV])
AC_SUBST([PIC_CFLAGS]) AC_SUBST([PIC_CFLAGS])
AC_SUBST([CTARGET]) AC_SUBST([CTARGET])
AC_SUBST([LDTARGET]) AC_SUBST([LDTARGET])
AC_SUBST([TEST_LD_MODE])
AC_SUBST([MKLIB]) AC_SUBST([MKLIB])
AC_SUBST([ARFLAGS]) AC_SUBST([ARFLAGS])
AC_SUBST([AROUT]) AC_SUBST([AROUT])
AC_SUBST([CC_MM]) AC_SUBST([CC_MM])
dnl Determine whether libm must be linked to use e.g. log(3).
AC_SEARCH_LIBS([log], [m], , [AC_MSG_ERROR([Missing math functions])])
if test "x$ac_cv_search_log" != "xnone required" ; then
LM="$ac_cv_search_log"
else
LM=
fi
AC_SUBST(LM)
JE_COMPILABLE([__attribute__ syntax], JE_COMPILABLE([__attribute__ syntax],
[static __attribute__((unused)) void foo(void){}], [static __attribute__((unused)) void foo(void){}],
[], [],
@@ -444,18 +550,19 @@ JE_COMPILABLE([__attribute__ syntax],
if test "x${je_cv_attribute}" = "xyes" ; then if test "x${je_cv_attribute}" = "xyes" ; then
AC_DEFINE([JEMALLOC_HAVE_ATTR], [ ]) AC_DEFINE([JEMALLOC_HAVE_ATTR], [ ])
if test "x${GCC}" = "xyes" -a "x${abi}" = "xelf"; then if test "x${GCC}" = "xyes" -a "x${abi}" = "xelf"; then
JE_CFLAGS_APPEND([-fvisibility=hidden]) JE_CFLAGS_ADD([-fvisibility=hidden])
fi fi
fi fi
dnl Check for tls_model attribute support (clang 3.0 still lacks support). dnl Check for tls_model attribute support (clang 3.0 still lacks support).
SAVED_CFLAGS="${CFLAGS}" JE_CFLAGS_SAVE()
JE_CFLAGS_APPEND([-Werror]) JE_CFLAGS_ADD([-Werror])
JE_CFLAGS_ADD([-herror_on_warning])
JE_COMPILABLE([tls_model attribute], [], JE_COMPILABLE([tls_model attribute], [],
[static __thread int [static __thread int
__attribute__((tls_model("initial-exec"), unused)) foo; __attribute__((tls_model("initial-exec"), unused)) foo;
foo = 0;], foo = 0;],
[je_cv_tls_model]) [je_cv_tls_model])
CFLAGS="${SAVED_CFLAGS}" JE_CFLAGS_RESTORE()
if test "x${je_cv_tls_model}" = "xyes" ; then if test "x${je_cv_tls_model}" = "xyes" ; then
AC_DEFINE([JEMALLOC_TLS_MODEL], AC_DEFINE([JEMALLOC_TLS_MODEL],
[__attribute__((tls_model("initial-exec")))]) [__attribute__((tls_model("initial-exec")))])
@@ -463,32 +570,35 @@ else
AC_DEFINE([JEMALLOC_TLS_MODEL], [ ]) AC_DEFINE([JEMALLOC_TLS_MODEL], [ ])
fi fi
dnl Check for alloc_size attribute support. dnl Check for alloc_size attribute support.
SAVED_CFLAGS="${CFLAGS}" JE_CFLAGS_SAVE()
JE_CFLAGS_APPEND([-Werror]) JE_CFLAGS_ADD([-Werror])
JE_CFLAGS_ADD([-herror_on_warning])
JE_COMPILABLE([alloc_size attribute], [#include <stdlib.h>], JE_COMPILABLE([alloc_size attribute], [#include <stdlib.h>],
[void *foo(size_t size) __attribute__((alloc_size(1)));], [void *foo(size_t size) __attribute__((alloc_size(1)));],
[je_cv_alloc_size]) [je_cv_alloc_size])
CFLAGS="${SAVED_CFLAGS}" JE_CFLAGS_RESTORE()
if test "x${je_cv_alloc_size}" = "xyes" ; then if test "x${je_cv_alloc_size}" = "xyes" ; then
AC_DEFINE([JEMALLOC_HAVE_ATTR_ALLOC_SIZE], [ ]) AC_DEFINE([JEMALLOC_HAVE_ATTR_ALLOC_SIZE], [ ])
fi fi
dnl Check for format(gnu_printf, ...) attribute support. dnl Check for format(gnu_printf, ...) attribute support.
SAVED_CFLAGS="${CFLAGS}" JE_CFLAGS_SAVE()
JE_CFLAGS_APPEND([-Werror]) JE_CFLAGS_ADD([-Werror])
JE_CFLAGS_ADD([-herror_on_warning])
JE_COMPILABLE([format(gnu_printf, ...) attribute], [#include <stdlib.h>], JE_COMPILABLE([format(gnu_printf, ...) attribute], [#include <stdlib.h>],
[void *foo(const char *format, ...) __attribute__((format(gnu_printf, 1, 2)));], [void *foo(const char *format, ...) __attribute__((format(gnu_printf, 1, 2)));],
[je_cv_format_gnu_printf]) [je_cv_format_gnu_printf])
CFLAGS="${SAVED_CFLAGS}" JE_CFLAGS_RESTORE()
if test "x${je_cv_format_gnu_printf}" = "xyes" ; then if test "x${je_cv_format_gnu_printf}" = "xyes" ; then
AC_DEFINE([JEMALLOC_HAVE_ATTR_FORMAT_GNU_PRINTF], [ ]) AC_DEFINE([JEMALLOC_HAVE_ATTR_FORMAT_GNU_PRINTF], [ ])
fi fi
dnl Check for format(printf, ...) attribute support. dnl Check for format(printf, ...) attribute support.
SAVED_CFLAGS="${CFLAGS}" JE_CFLAGS_SAVE()
JE_CFLAGS_APPEND([-Werror]) JE_CFLAGS_ADD([-Werror])
JE_CFLAGS_ADD([-herror_on_warning])
JE_COMPILABLE([format(printf, ...) attribute], [#include <stdlib.h>], JE_COMPILABLE([format(printf, ...) attribute], [#include <stdlib.h>],
[void *foo(const char *format, ...) __attribute__((format(printf, 1, 2)));], [void *foo(const char *format, ...) __attribute__((format(printf, 1, 2)));],
[je_cv_format_printf]) [je_cv_format_printf])
CFLAGS="${SAVED_CFLAGS}" JE_CFLAGS_RESTORE()
if test "x${je_cv_format_printf}" = "xyes" ; then if test "x${je_cv_format_printf}" = "xyes" ; then
AC_DEFINE([JEMALLOC_HAVE_ATTR_FORMAT_PRINTF], [ ]) AC_DEFINE([JEMALLOC_HAVE_ATTR_FORMAT_PRINTF], [ ])
fi fi
@@ -550,9 +660,9 @@ if test "x$enable_code_coverage" = "x1" ; then
deoptimize="no" deoptimize="no"
echo "$CFLAGS $EXTRA_CFLAGS" | grep '\-O' >/dev/null || deoptimize="yes" echo "$CFLAGS $EXTRA_CFLAGS" | grep '\-O' >/dev/null || deoptimize="yes"
if test "x${deoptimize}" = "xyes" ; then if test "x${deoptimize}" = "xyes" ; then
JE_CFLAGS_APPEND([-O0]) JE_CFLAGS_ADD([-O0])
fi fi
JE_CFLAGS_APPEND([-fprofile-arcs -ftest-coverage]) JE_CFLAGS_ADD([-fprofile-arcs -ftest-coverage])
EXTRA_LDFLAGS="$EXTRA_LDFLAGS -fprofile-arcs -ftest-coverage" EXTRA_LDFLAGS="$EXTRA_LDFLAGS -fprofile-arcs -ftest-coverage"
AC_DEFINE([JEMALLOC_CODE_COVERAGE], [ ]) AC_DEFINE([JEMALLOC_CODE_COVERAGE], [ ])
fi fi
@@ -742,19 +852,14 @@ if test "x$enable_ivsalloc" = "x1" ; then
fi fi
dnl Only optimize if not debugging. dnl Only optimize if not debugging.
if test "x$enable_debug" = "x0" -a "x$no_CFLAGS" = "xyes" ; then if test "x$enable_debug" = "x0" ; then
dnl Make sure that an optimization flag was not specified in EXTRA_CFLAGS. if test "x$GCC" = "xyes" ; then
optimize="no" JE_CFLAGS_ADD([-O3])
echo "$CFLAGS $EXTRA_CFLAGS" | grep '\-O' >/dev/null || optimize="yes" JE_CFLAGS_ADD([-funroll-loops])
if test "x${optimize}" = "xyes" ; then elif test "x$je_cv_msvc" = "xyes" ; then
if test "x$GCC" = "xyes" ; then JE_CFLAGS_ADD([-O2])
JE_CFLAGS_APPEND([-O3]) else
JE_CFLAGS_APPEND([-funroll-loops]) JE_CFLAGS_ADD([-O])
elif test "x$je_cv_msvc" = "xyes" ; then
JE_CFLAGS_APPEND([-O2])
else
JE_CFLAGS_APPEND([-O])
fi
fi fi
fi fi
@@ -818,10 +923,10 @@ fi,
if test "x$backtrace_method" = "x" -a "x$enable_prof_libunwind" = "x1" ; then if test "x$backtrace_method" = "x" -a "x$enable_prof_libunwind" = "x1" ; then
AC_CHECK_HEADERS([libunwind.h], , [enable_prof_libunwind="0"]) AC_CHECK_HEADERS([libunwind.h], , [enable_prof_libunwind="0"])
if test "x$LUNWIND" = "x-lunwind" ; then if test "x$LUNWIND" = "x-lunwind" ; then
AC_CHECK_LIB([unwind], [unw_backtrace], [LIBS="$LIBS $LUNWIND"], AC_CHECK_LIB([unwind], [unw_backtrace], [JE_APPEND_VS(LIBS, $LUNWIND)],
[enable_prof_libunwind="0"]) [enable_prof_libunwind="0"])
else else
LIBS="$LIBS $LUNWIND" JE_APPEND_VS(LIBS, $LUNWIND)
fi fi
if test "x${enable_prof_libunwind}" = "x1" ; then if test "x${enable_prof_libunwind}" = "x1" ; then
backtrace_method="libunwind" backtrace_method="libunwind"
@@ -843,7 +948,7 @@ fi
if test "x$backtrace_method" = "x" -a "x$enable_prof_libgcc" = "x1" \ if test "x$backtrace_method" = "x" -a "x$enable_prof_libgcc" = "x1" \
-a "x$GCC" = "xyes" ; then -a "x$GCC" = "xyes" ; then
AC_CHECK_HEADERS([unwind.h], , [enable_prof_libgcc="0"]) AC_CHECK_HEADERS([unwind.h], , [enable_prof_libgcc="0"])
AC_CHECK_LIB([gcc], [_Unwind_Backtrace], [LIBS="$LIBS -lgcc"], [enable_prof_libgcc="0"]) AC_CHECK_LIB([gcc], [_Unwind_Backtrace], [JE_APPEND_VS(LIBS, -lgcc)], [enable_prof_libgcc="0"])
if test "x${enable_prof_libgcc}" = "x1" ; then if test "x${enable_prof_libgcc}" = "x1" ; then
backtrace_method="libgcc" backtrace_method="libgcc"
AC_DEFINE([JEMALLOC_PROF_LIBGCC], [ ]) AC_DEFINE([JEMALLOC_PROF_LIBGCC], [ ])
@@ -865,7 +970,7 @@ fi
) )
if test "x$backtrace_method" = "x" -a "x$enable_prof_gcc" = "x1" \ if test "x$backtrace_method" = "x" -a "x$enable_prof_gcc" = "x1" \
-a "x$GCC" = "xyes" ; then -a "x$GCC" = "xyes" ; then
JE_CFLAGS_APPEND([-fno-omit-frame-pointer]) JE_CFLAGS_ADD([-fno-omit-frame-pointer])
backtrace_method="gcc intrinsics" backtrace_method="gcc intrinsics"
AC_DEFINE([JEMALLOC_PROF_GCC], [ ]) AC_DEFINE([JEMALLOC_PROF_GCC], [ ])
else else
@@ -879,10 +984,8 @@ fi
AC_MSG_CHECKING([configured backtracing method]) AC_MSG_CHECKING([configured backtracing method])
AC_MSG_RESULT([$backtrace_method]) AC_MSG_RESULT([$backtrace_method])
if test "x$enable_prof" = "x1" ; then if test "x$enable_prof" = "x1" ; then
if test "x$abi" != "xpecoff"; then dnl Heap profiling uses the log(3) function.
dnl Heap profiling uses the log(3) function. JE_APPEND_VS(LIBS, $LM)
LIBS="$LIBS -lm"
fi
AC_DEFINE([JEMALLOC_PROF], [ ]) AC_DEFINE([JEMALLOC_PROF], [ ])
fi fi
@@ -1050,6 +1153,23 @@ if test "x$enable_cache_oblivious" = "x1" ; then
fi fi
AC_SUBST([enable_cache_oblivious]) AC_SUBST([enable_cache_oblivious])
JE_COMPILABLE([a program using __builtin_unreachable], [
void foo (void) {
__builtin_unreachable();
}
], [
{
foo();
}
], [je_cv_gcc_builtin_unreachable])
if test "x${je_cv_gcc_builtin_unreachable}" = "xyes" ; then
AC_DEFINE([JEMALLOC_INTERNAL_UNREACHABLE], [__builtin_unreachable])
else
AC_DEFINE([JEMALLOC_INTERNAL_UNREACHABLE], [abort])
fi
dnl ============================================================================ dnl ============================================================================
dnl Check for __builtin_ffsl(), then ffsl(3), and fail if neither are found. dnl Check for __builtin_ffsl(), then ffsl(3), and fail if neither are found.
dnl One of those two functions should (theoretically) exist on all platforms dnl One of those two functions should (theoretically) exist on all platforms
@@ -1234,16 +1354,105 @@ if test "x$abi" != "xpecoff" ; then
AC_CHECK_HEADERS([pthread.h], , [AC_MSG_ERROR([pthread.h is missing])]) AC_CHECK_HEADERS([pthread.h], , [AC_MSG_ERROR([pthread.h is missing])])
dnl Some systems may embed pthreads functionality in libc; check for libpthread dnl Some systems may embed pthreads functionality in libc; check for libpthread
dnl first, but try libc too before failing. dnl first, but try libc too before failing.
AC_CHECK_LIB([pthread], [pthread_create], [LIBS="$LIBS -lpthread"], AC_CHECK_LIB([pthread], [pthread_create], [JE_APPEND_VS(LIBS, -lpthread)],
[AC_SEARCH_LIBS([pthread_create], , , [AC_SEARCH_LIBS([pthread_create], , ,
AC_MSG_ERROR([libpthread is missing]))]) AC_MSG_ERROR([libpthread is missing]))])
JE_COMPILABLE([pthread_atfork(3)], [
#include <pthread.h>
], [
pthread_atfork((void *)0, (void *)0, (void *)0);
], [je_cv_pthread_atfork])
if test "x${je_cv_pthread_atfork}" = "xyes" ; then
AC_DEFINE([JEMALLOC_HAVE_PTHREAD_ATFORK], [ ])
fi
fi fi
CPPFLAGS="$CPPFLAGS -D_REENTRANT" JE_APPEND_VS(CPPFLAGS, -D_REENTRANT)
dnl Check whether clock_gettime(2) is in libc or librt. dnl Check whether clock_gettime(2) is in libc or librt.
AC_SEARCH_LIBS([clock_gettime], [rt]) AC_SEARCH_LIBS([clock_gettime], [rt])
dnl Cray wrapper compiler often adds `-lrt` when using `-static`. Check with
dnl `-dynamic` as well in case a user tries to dynamically link in jemalloc
if test "x$je_cv_cray_prgenv_wrapper" = "xyes" ; then
if test "$ac_cv_search_clock_gettime" != "-lrt"; then
JE_CFLAGS_SAVE()
unset ac_cv_search_clock_gettime
JE_CFLAGS_ADD([-dynamic])
AC_SEARCH_LIBS([clock_gettime], [rt])
JE_CFLAGS_RESTORE()
fi
fi
dnl check for CLOCK_MONOTONIC_COARSE (Linux-specific).
JE_COMPILABLE([clock_gettime(CLOCK_MONOTONIC_COARSE, ...)], [
#include <time.h>
], [
struct timespec ts;
clock_gettime(CLOCK_MONOTONIC_COARSE, &ts);
], [je_cv_clock_monotonic_coarse])
if test "x${je_cv_clock_monotonic_coarse}" = "xyes" ; then
AC_DEFINE([JEMALLOC_HAVE_CLOCK_MONOTONIC_COARSE])
fi
dnl check for CLOCK_MONOTONIC.
JE_COMPILABLE([clock_gettime(CLOCK_MONOTONIC, ...)], [
#include <unistd.h>
#include <time.h>
], [
struct timespec ts;
clock_gettime(CLOCK_MONOTONIC, &ts);
#if !defined(_POSIX_MONOTONIC_CLOCK) || _POSIX_MONOTONIC_CLOCK < 0
# error _POSIX_MONOTONIC_CLOCK missing/invalid
#endif
], [je_cv_clock_monotonic])
if test "x${je_cv_clock_monotonic}" = "xyes" ; then
AC_DEFINE([JEMALLOC_HAVE_CLOCK_MONOTONIC])
fi
dnl Check for mach_absolute_time().
JE_COMPILABLE([mach_absolute_time()], [
#include <mach/mach_time.h>
], [
mach_absolute_time();
], [je_cv_mach_absolute_time])
if test "x${je_cv_mach_absolute_time}" = "xyes" ; then
AC_DEFINE([JEMALLOC_HAVE_MACH_ABSOLUTE_TIME])
fi
dnl Use syscall(2) (if available) by default.
AC_ARG_ENABLE([syscall],
[AS_HELP_STRING([--disable-syscall], [Disable use of syscall(2)])],
[if test "x$enable_syscall" = "xno" ; then
enable_syscall="0"
else
enable_syscall="1"
fi
],
[enable_syscall="1"]
)
if test "x$enable_syscall" = "x1" ; then
dnl Check if syscall(2) is usable. Treat warnings as errors, so that e.g. OS
dnl X 10.12's deprecation warning prevents use.
JE_CFLAGS_SAVE()
JE_CFLAGS_ADD([-Werror])
JE_COMPILABLE([syscall(2)], [
#include <sys/syscall.h>
#include <unistd.h>
], [
syscall(SYS_write, 2, "hello", 5);
],
[je_cv_syscall])
JE_CFLAGS_RESTORE()
if test "x$je_cv_syscall" = "xyes" ; then
AC_DEFINE([JEMALLOC_USE_SYSCALL], [ ])
fi
fi
dnl Check if the GNU-specific secure_getenv function exists. dnl Check if the GNU-specific secure_getenv function exists.
AC_CHECK_FUNC([secure_getenv], AC_CHECK_FUNC([secure_getenv],
[have_secure_getenv="1"], [have_secure_getenv="1"],
@@ -1298,21 +1507,27 @@ fi
], ],
[enable_lazy_lock=""] [enable_lazy_lock=""]
) )
if test "x$enable_lazy_lock" = "x" -a "x${force_lazy_lock}" = "x1" ; then if test "x${enable_lazy_lock}" = "x" ; then
AC_MSG_RESULT([Forcing lazy-lock to avoid allocator/threading bootstrap issues]) if test "x${force_lazy_lock}" = "x1" ; then
enable_lazy_lock="1" AC_MSG_RESULT([Forcing lazy-lock to avoid allocator/threading bootstrap issues])
enable_lazy_lock="1"
else
enable_lazy_lock="0"
fi
fi
if test "x${enable_lazy_lock}" = "x1" -a "x${abi}" = "xpecoff" ; then
AC_MSG_RESULT([Forcing no lazy-lock because thread creation monitoring is unimplemented])
enable_lazy_lock="0"
fi fi
if test "x$enable_lazy_lock" = "x1" ; then if test "x$enable_lazy_lock" = "x1" ; then
if test "x$abi" != "xpecoff" ; then if test "x$abi" != "xpecoff" ; then
AC_CHECK_HEADERS([dlfcn.h], , [AC_MSG_ERROR([dlfcn.h is missing])]) AC_CHECK_HEADERS([dlfcn.h], , [AC_MSG_ERROR([dlfcn.h is missing])])
AC_CHECK_FUNC([dlsym], [], AC_CHECK_FUNC([dlsym], [],
[AC_CHECK_LIB([dl], [dlsym], [LIBS="$LIBS -ldl"], [AC_CHECK_LIB([dl], [dlsym], [JE_APPEND_VS(LIBS, -ldl)],
[AC_MSG_ERROR([libdl is missing])]) [AC_MSG_ERROR([libdl is missing])])
]) ])
fi fi
AC_DEFINE([JEMALLOC_LAZY_LOCK], [ ]) AC_DEFINE([JEMALLOC_LAZY_LOCK], [ ])
else
enable_lazy_lock="0"
fi fi
AC_SUBST([enable_lazy_lock]) AC_SUBST([enable_lazy_lock])
@@ -1435,14 +1650,64 @@ dnl Check for madvise(2).
JE_COMPILABLE([madvise(2)], [ JE_COMPILABLE([madvise(2)], [
#include <sys/mman.h> #include <sys/mman.h>
], [ ], [
{ madvise((void *)0, 0, 0);
madvise((void *)0, 0, 0);
}
], [je_cv_madvise]) ], [je_cv_madvise])
if test "x${je_cv_madvise}" = "xyes" ; then if test "x${je_cv_madvise}" = "xyes" ; then
AC_DEFINE([JEMALLOC_HAVE_MADVISE], [ ]) AC_DEFINE([JEMALLOC_HAVE_MADVISE], [ ])
dnl Check for madvise(..., MADV_FREE).
JE_COMPILABLE([madvise(..., MADV_FREE)], [
#include <sys/mman.h>
], [
madvise((void *)0, 0, MADV_FREE);
], [je_cv_madv_free])
if test "x${je_cv_madv_free}" = "xyes" ; then
AC_DEFINE([JEMALLOC_PURGE_MADVISE_FREE], [ ])
fi
dnl Check for madvise(..., MADV_DONTNEED).
JE_COMPILABLE([madvise(..., MADV_DONTNEED)], [
#include <sys/mman.h>
], [
madvise((void *)0, 0, MADV_DONTNEED);
], [je_cv_madv_dontneed])
if test "x${je_cv_madv_dontneed}" = "xyes" ; then
AC_DEFINE([JEMALLOC_PURGE_MADVISE_DONTNEED], [ ])
fi
dnl Check for madvise(..., MADV_[NO]HUGEPAGE).
JE_COMPILABLE([madvise(..., MADV_[[NO]]HUGEPAGE)], [
#include <sys/mman.h>
], [
madvise((void *)0, 0, MADV_HUGEPAGE);
madvise((void *)0, 0, MADV_NOHUGEPAGE);
], [je_cv_thp])
if test "x${je_cv_thp}" = "xyes" ; then
AC_DEFINE([JEMALLOC_HAVE_MADVISE_HUGE], [ ])
fi
fi fi
dnl Enable transparent huge page support by default.
AC_ARG_ENABLE([thp],
[AS_HELP_STRING([--disable-thp],
[Disable transparent huge page supprot])],
[if test "x$enable_thp" = "xno" -o "x${je_cv_thp}" != "xyes" ; then
enable_thp="0"
else
enable_thp="1"
fi
],
[if test "x${je_cv_thp}" = "xyes" ; then
enable_thp="1"
else
enable_thp="0"
fi
])
if test "x$enable_thp" = "x1" ; then
AC_DEFINE([JEMALLOC_THP], [ ])
fi
AC_SUBST([enable_thp])
dnl ============================================================================ dnl ============================================================================
dnl Check whether __sync_{add,sub}_and_fetch() are available despite dnl Check whether __sync_{add,sub}_and_fetch() are available despite
dnl __GCC_HAVE_SYNC_COMPARE_AND_SWAP_n macros being undefined. dnl __GCC_HAVE_SYNC_COMPARE_AND_SWAP_n macros being undefined.
@@ -1500,6 +1765,25 @@ if test "x${je_cv_builtin_clz}" = "xyes" ; then
AC_DEFINE([JEMALLOC_HAVE_BUILTIN_CLZ], [ ]) AC_DEFINE([JEMALLOC_HAVE_BUILTIN_CLZ], [ ])
fi fi
dnl ============================================================================
dnl Check for os_unfair_lock operations as provided on Darwin.
JE_COMPILABLE([Darwin os_unfair_lock_*()], [
#include <os/lock.h>
#include <AvailabilityMacros.h>
], [
#if MAC_OS_X_VERSION_MIN_REQUIRED < 101200
#error "os_unfair_lock is not supported"
#else
os_unfair_lock lock = OS_UNFAIR_LOCK_INIT;
os_unfair_lock_lock(&lock);
os_unfair_lock_unlock(&lock);
#endif
], [je_cv_os_unfair_lock])
if test "x${je_cv_os_unfair_lock}" = "xyes" ; then
AC_DEFINE([JEMALLOC_OS_UNFAIR_LOCK], [ ])
fi
dnl ============================================================================ dnl ============================================================================
dnl Check for spinlock(3) operations as provided on Darwin. dnl Check for spinlock(3) operations as provided on Darwin.
@@ -1539,37 +1823,6 @@ if test "x${enable_zone_allocator}" = "x1" ; then
AC_MSG_ERROR([--enable-zone-allocator is only supported on Darwin]) AC_MSG_ERROR([--enable-zone-allocator is only supported on Darwin])
fi fi
AC_DEFINE([JEMALLOC_ZONE], [ ]) AC_DEFINE([JEMALLOC_ZONE], [ ])
dnl The szone version jumped from 3 to 6 between the OS X 10.5.x and 10.6
dnl releases. malloc_zone_t and malloc_introspection_t have new fields in
dnl 10.6, which is the only source-level indication of the change.
AC_MSG_CHECKING([malloc zone version])
AC_DEFUN([JE_ZONE_PROGRAM],
[AC_LANG_PROGRAM(
[#include <malloc/malloc.h>],
[static int foo[[sizeof($1) $2 sizeof(void *) * $3 ? 1 : -1]]]
)])
AC_COMPILE_IFELSE([JE_ZONE_PROGRAM(malloc_zone_t,==,14)],[JEMALLOC_ZONE_VERSION=3],[
AC_COMPILE_IFELSE([JE_ZONE_PROGRAM(malloc_zone_t,==,15)],[JEMALLOC_ZONE_VERSION=5],[
AC_COMPILE_IFELSE([JE_ZONE_PROGRAM(malloc_zone_t,==,16)],[
AC_COMPILE_IFELSE([JE_ZONE_PROGRAM(malloc_introspection_t,==,9)],[JEMALLOC_ZONE_VERSION=6],[
AC_COMPILE_IFELSE([JE_ZONE_PROGRAM(malloc_introspection_t,==,13)],[JEMALLOC_ZONE_VERSION=7],[JEMALLOC_ZONE_VERSION=]
)])],[
AC_COMPILE_IFELSE([JE_ZONE_PROGRAM(malloc_zone_t,==,17)],[JEMALLOC_ZONE_VERSION=8],[
AC_COMPILE_IFELSE([JE_ZONE_PROGRAM(malloc_zone_t,>,17)],[JEMALLOC_ZONE_VERSION=9],[JEMALLOC_ZONE_VERSION=]
)])])])])
if test "x${JEMALLOC_ZONE_VERSION}" = "x"; then
AC_MSG_RESULT([unsupported])
AC_MSG_ERROR([Unsupported malloc zone version])
fi
if test "${JEMALLOC_ZONE_VERSION}" = 9; then
JEMALLOC_ZONE_VERSION=8
AC_MSG_RESULT([> 8])
else
AC_MSG_RESULT([$JEMALLOC_ZONE_VERSION])
fi
AC_DEFINE_UNQUOTED(JEMALLOC_ZONE_VERSION, [$JEMALLOC_ZONE_VERSION])
fi fi
dnl ============================================================================ dnl ============================================================================
@@ -1743,7 +1996,9 @@ AC_MSG_RESULT([library revision : ${rev}])
AC_MSG_RESULT([]) AC_MSG_RESULT([])
AC_MSG_RESULT([CONFIG : ${CONFIG}]) AC_MSG_RESULT([CONFIG : ${CONFIG}])
AC_MSG_RESULT([CC : ${CC}]) AC_MSG_RESULT([CC : ${CC}])
AC_MSG_RESULT([CFLAGS : ${CFLAGS}]) AC_MSG_RESULT([CONFIGURE_CFLAGS : ${CONFIGURE_CFLAGS}])
AC_MSG_RESULT([SPECIFIED_CFLAGS : ${SPECIFIED_CFLAGS}])
AC_MSG_RESULT([EXTRA_CFLAGS : ${EXTRA_CFLAGS}])
AC_MSG_RESULT([CPPFLAGS : ${CPPFLAGS}]) AC_MSG_RESULT([CPPFLAGS : ${CPPFLAGS}])
AC_MSG_RESULT([LDFLAGS : ${LDFLAGS}]) AC_MSG_RESULT([LDFLAGS : ${LDFLAGS}])
AC_MSG_RESULT([EXTRA_LDFLAGS : ${EXTRA_LDFLAGS}]) AC_MSG_RESULT([EXTRA_LDFLAGS : ${EXTRA_LDFLAGS}])
@@ -1780,6 +2035,7 @@ AC_MSG_RESULT([prof-libunwind : ${enable_prof_libunwind}])
AC_MSG_RESULT([prof-libgcc : ${enable_prof_libgcc}]) AC_MSG_RESULT([prof-libgcc : ${enable_prof_libgcc}])
AC_MSG_RESULT([prof-gcc : ${enable_prof_gcc}]) AC_MSG_RESULT([prof-gcc : ${enable_prof_gcc}])
AC_MSG_RESULT([tcache : ${enable_tcache}]) AC_MSG_RESULT([tcache : ${enable_tcache}])
AC_MSG_RESULT([thp : ${enable_thp}])
AC_MSG_RESULT([fill : ${enable_fill}]) AC_MSG_RESULT([fill : ${enable_fill}])
AC_MSG_RESULT([utrace : ${enable_utrace}]) AC_MSG_RESULT([utrace : ${enable_utrace}])
AC_MSG_RESULT([valgrind : ${enable_valgrind}]) AC_MSG_RESULT([valgrind : ${enable_valgrind}])

View File

@@ -1,4 +1,5 @@
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"> <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:import href="@XSLROOT@/html/docbook.xsl"/> <xsl:import href="@XSLROOT@/html/docbook.xsl"/>
<xsl:import href="@abs_srcroot@doc/stylesheet.xsl"/> <xsl:import href="@abs_srcroot@doc/stylesheet.xsl"/>
<xsl:output method="xml" encoding="utf-8"/>
</xsl:stylesheet> </xsl:stylesheet>

View File

@@ -52,7 +52,7 @@
<title>LIBRARY</title> <title>LIBRARY</title>
<para>This manual describes jemalloc @jemalloc_version@. More information <para>This manual describes jemalloc @jemalloc_version@. More information
can be found at the <ulink can be found at the <ulink
url="http://www.canonware.com/jemalloc/">jemalloc website</ulink>.</para> url="http://jemalloc.net/">jemalloc website</ulink>.</para>
</refsect1> </refsect1>
<refsynopsisdiv> <refsynopsisdiv>
<title>SYNOPSIS</title> <title>SYNOPSIS</title>
@@ -180,20 +180,20 @@
<refsect2> <refsect2>
<title>Standard API</title> <title>Standard API</title>
<para>The <function>malloc<parameter/></function> function allocates <para>The <function>malloc()</function> function allocates
<parameter>size</parameter> bytes of uninitialized memory. The allocated <parameter>size</parameter> bytes of uninitialized memory. The allocated
space is suitably aligned (after possible pointer coercion) for storage space is suitably aligned (after possible pointer coercion) for storage
of any type of object.</para> of any type of object.</para>
<para>The <function>calloc<parameter/></function> function allocates <para>The <function>calloc()</function> function allocates
space for <parameter>number</parameter> objects, each space for <parameter>number</parameter> objects, each
<parameter>size</parameter> bytes in length. The result is identical to <parameter>size</parameter> bytes in length. The result is identical to
calling <function>malloc<parameter/></function> with an argument of calling <function>malloc()</function> with an argument of
<parameter>number</parameter> * <parameter>size</parameter>, with the <parameter>number</parameter> * <parameter>size</parameter>, with the
exception that the allocated memory is explicitly initialized to zero exception that the allocated memory is explicitly initialized to zero
bytes.</para> bytes.</para>
<para>The <function>posix_memalign<parameter/></function> function <para>The <function>posix_memalign()</function> function
allocates <parameter>size</parameter> bytes of memory such that the allocates <parameter>size</parameter> bytes of memory such that the
allocation's base address is a multiple of allocation's base address is a multiple of
<parameter>alignment</parameter>, and returns the allocation in the value <parameter>alignment</parameter>, and returns the allocation in the value
@@ -201,7 +201,7 @@
<parameter>alignment</parameter> must be a power of 2 at least as large as <parameter>alignment</parameter> must be a power of 2 at least as large as
<code language="C">sizeof(<type>void *</type>)</code>.</para> <code language="C">sizeof(<type>void *</type>)</code>.</para>
<para>The <function>aligned_alloc<parameter/></function> function <para>The <function>aligned_alloc()</function> function
allocates <parameter>size</parameter> bytes of memory such that the allocates <parameter>size</parameter> bytes of memory such that the
allocation's base address is a multiple of allocation's base address is a multiple of
<parameter>alignment</parameter>. The requested <parameter>alignment</parameter>. The requested
@@ -209,7 +209,7 @@
undefined if <parameter>size</parameter> is not an integral multiple of undefined if <parameter>size</parameter> is not an integral multiple of
<parameter>alignment</parameter>.</para> <parameter>alignment</parameter>.</para>
<para>The <function>realloc<parameter/></function> function changes the <para>The <function>realloc()</function> function changes the
size of the previously allocated memory referenced by size of the previously allocated memory referenced by
<parameter>ptr</parameter> to <parameter>size</parameter> bytes. The <parameter>ptr</parameter> to <parameter>size</parameter> bytes. The
contents of the memory are unchanged up to the lesser of the new and old contents of the memory are unchanged up to the lesser of the new and old
@@ -217,26 +217,26 @@
portion of the memory are undefined. Upon success, the memory referenced portion of the memory are undefined. Upon success, the memory referenced
by <parameter>ptr</parameter> is freed and a pointer to the newly by <parameter>ptr</parameter> is freed and a pointer to the newly
allocated memory is returned. Note that allocated memory is returned. Note that
<function>realloc<parameter/></function> may move the memory allocation, <function>realloc()</function> may move the memory allocation,
resulting in a different return value than <parameter>ptr</parameter>. resulting in a different return value than <parameter>ptr</parameter>.
If <parameter>ptr</parameter> is <constant>NULL</constant>, the If <parameter>ptr</parameter> is <constant>NULL</constant>, the
<function>realloc<parameter/></function> function behaves identically to <function>realloc()</function> function behaves identically to
<function>malloc<parameter/></function> for the specified size.</para> <function>malloc()</function> for the specified size.</para>
<para>The <function>free<parameter/></function> function causes the <para>The <function>free()</function> function causes the
allocated memory referenced by <parameter>ptr</parameter> to be made allocated memory referenced by <parameter>ptr</parameter> to be made
available for future allocations. If <parameter>ptr</parameter> is available for future allocations. If <parameter>ptr</parameter> is
<constant>NULL</constant>, no action occurs.</para> <constant>NULL</constant>, no action occurs.</para>
</refsect2> </refsect2>
<refsect2> <refsect2>
<title>Non-standard API</title> <title>Non-standard API</title>
<para>The <function>mallocx<parameter/></function>, <para>The <function>mallocx()</function>,
<function>rallocx<parameter/></function>, <function>rallocx()</function>,
<function>xallocx<parameter/></function>, <function>xallocx()</function>,
<function>sallocx<parameter/></function>, <function>sallocx()</function>,
<function>dallocx<parameter/></function>, <function>dallocx()</function>,
<function>sdallocx<parameter/></function>, and <function>sdallocx()</function>, and
<function>nallocx<parameter/></function> functions all have a <function>nallocx()</function> functions all have a
<parameter>flags</parameter> argument that can be used to specify <parameter>flags</parameter> argument that can be used to specify
options. The functions only check the options that are contextually options. The functions only check the options that are contextually
relevant. Use bitwise or (<code language="C">|</code>) operations to relevant. Use bitwise or (<code language="C">|</code>) operations to
@@ -307,19 +307,19 @@
</variablelist> </variablelist>
</para> </para>
<para>The <function>mallocx<parameter/></function> function allocates at <para>The <function>mallocx()</function> function allocates at
least <parameter>size</parameter> bytes of memory, and returns a pointer least <parameter>size</parameter> bytes of memory, and returns a pointer
to the base address of the allocation. Behavior is undefined if to the base address of the allocation. Behavior is undefined if
<parameter>size</parameter> is <constant>0</constant>.</para> <parameter>size</parameter> is <constant>0</constant>.</para>
<para>The <function>rallocx<parameter/></function> function resizes the <para>The <function>rallocx()</function> function resizes the
allocation at <parameter>ptr</parameter> to be at least allocation at <parameter>ptr</parameter> to be at least
<parameter>size</parameter> bytes, and returns a pointer to the base <parameter>size</parameter> bytes, and returns a pointer to the base
address of the resulting allocation, which may or may not have moved from address of the resulting allocation, which may or may not have moved from
its original location. Behavior is undefined if its original location. Behavior is undefined if
<parameter>size</parameter> is <constant>0</constant>.</para> <parameter>size</parameter> is <constant>0</constant>.</para>
<para>The <function>xallocx<parameter/></function> function resizes the <para>The <function>xallocx()</function> function resizes the
allocation at <parameter>ptr</parameter> in place to be at least allocation at <parameter>ptr</parameter> in place to be at least
<parameter>size</parameter> bytes, and returns the real size of the <parameter>size</parameter> bytes, and returns the real size of the
allocation. If <parameter>extra</parameter> is non-zero, an attempt is allocation. If <parameter>extra</parameter> is non-zero, an attempt is
@@ -332,32 +332,32 @@
language="C">(<parameter>size</parameter> + <parameter>extra</parameter> language="C">(<parameter>size</parameter> + <parameter>extra</parameter>
&gt; <constant>SIZE_T_MAX</constant>)</code>.</para> &gt; <constant>SIZE_T_MAX</constant>)</code>.</para>
<para>The <function>sallocx<parameter/></function> function returns the <para>The <function>sallocx()</function> function returns the
real size of the allocation at <parameter>ptr</parameter>.</para> real size of the allocation at <parameter>ptr</parameter>.</para>
<para>The <function>dallocx<parameter/></function> function causes the <para>The <function>dallocx()</function> function causes the
memory referenced by <parameter>ptr</parameter> to be made available for memory referenced by <parameter>ptr</parameter> to be made available for
future allocations.</para> future allocations.</para>
<para>The <function>sdallocx<parameter/></function> function is an <para>The <function>sdallocx()</function> function is an
extension of <function>dallocx<parameter/></function> with a extension of <function>dallocx()</function> with a
<parameter>size</parameter> parameter to allow the caller to pass in the <parameter>size</parameter> parameter to allow the caller to pass in the
allocation size as an optimization. The minimum valid input size is the allocation size as an optimization. The minimum valid input size is the
original requested size of the allocation, and the maximum valid input original requested size of the allocation, and the maximum valid input
size is the corresponding value returned by size is the corresponding value returned by
<function>nallocx<parameter/></function> or <function>nallocx()</function> or
<function>sallocx<parameter/></function>.</para> <function>sallocx()</function>.</para>
<para>The <function>nallocx<parameter/></function> function allocates no <para>The <function>nallocx()</function> function allocates no
memory, but it performs the same size computation as the memory, but it performs the same size computation as the
<function>mallocx<parameter/></function> function, and returns the real <function>mallocx()</function> function, and returns the real
size of the allocation that would result from the equivalent size of the allocation that would result from the equivalent
<function>mallocx<parameter/></function> function call, or <function>mallocx()</function> function call, or
<constant>0</constant> if the inputs exceed the maximum supported size <constant>0</constant> if the inputs exceed the maximum supported size
class and/or alignment. Behavior is undefined if class and/or alignment. Behavior is undefined if
<parameter>size</parameter> is <constant>0</constant>.</para> <parameter>size</parameter> is <constant>0</constant>.</para>
<para>The <function>mallctl<parameter/></function> function provides a <para>The <function>mallctl()</function> function provides a
general interface for introspecting the memory allocator, as well as general interface for introspecting the memory allocator, as well as
setting modifiable parameters and triggering actions. The setting modifiable parameters and triggering actions. The
period-separated <parameter>name</parameter> argument specifies a period-separated <parameter>name</parameter> argument specifies a
@@ -372,12 +372,12 @@
<parameter>newlen</parameter>; otherwise pass <constant>NULL</constant> <parameter>newlen</parameter>; otherwise pass <constant>NULL</constant>
and <constant>0</constant>.</para> and <constant>0</constant>.</para>
<para>The <function>mallctlnametomib<parameter/></function> function <para>The <function>mallctlnametomib()</function> function
provides a way to avoid repeated name lookups for applications that provides a way to avoid repeated name lookups for applications that
repeatedly query the same portion of the namespace, by translating a name repeatedly query the same portion of the namespace, by translating a name
to a &ldquo;Management Information Base&rdquo; (MIB) that can be passed to a <quote>Management Information Base</quote> (MIB) that can be passed
repeatedly to <function>mallctlbymib<parameter/></function>. Upon repeatedly to <function>mallctlbymib()</function>. Upon
successful return from <function>mallctlnametomib<parameter/></function>, successful return from <function>mallctlnametomib()</function>,
<parameter>mibp</parameter> contains an array of <parameter>mibp</parameter> contains an array of
<parameter>*miblenp</parameter> integers, where <parameter>*miblenp</parameter> integers, where
<parameter>*miblenp</parameter> is the lesser of the number of components <parameter>*miblenp</parameter> is the lesser of the number of components
@@ -406,43 +406,44 @@ for (i = 0; i < nbins; i++) {
mib[2] = i; mib[2] = i;
len = sizeof(bin_size); len = sizeof(bin_size);
mallctlbymib(mib, miblen, &bin_size, &len, NULL, 0); mallctlbymib(mib, miblen, (void *)&bin_size, &len, NULL, 0);
/* Do something with bin_size... */ /* Do something with bin_size... */
}]]></programlisting></para> }]]></programlisting></para>
<para>The <function>malloc_stats_print<parameter/></function> function <para>The <function>malloc_stats_print()</function> function writes
writes human-readable summary statistics via the summary statistics via the <parameter>write_cb</parameter> callback
<parameter>write_cb</parameter> callback function pointer and function pointer and <parameter>cbopaque</parameter> data passed to
<parameter>cbopaque</parameter> data passed to <parameter>write_cb</parameter>, or <function>malloc_message()</function>
<parameter>write_cb</parameter>, or if <parameter>write_cb</parameter> is <constant>NULL</constant>. The
<function>malloc_message<parameter/></function> if statistics are presented in human-readable form unless <quote>J</quote> is
<parameter>write_cb</parameter> is <constant>NULL</constant>. This specified as a character within the <parameter>opts</parameter> string, in
function can be called repeatedly. General information that never which case the statistics are presented in <ulink
changes during execution can be omitted by specifying "g" as a character url="http://www.json.org/">JSON format</ulink>. This function can be
called repeatedly. General information that never changes during
execution can be omitted by specifying <quote>g</quote> as a character
within the <parameter>opts</parameter> string. Note that within the <parameter>opts</parameter> string. Note that
<function>malloc_message<parameter/></function> uses the <function>malloc_message()</function> uses the
<function>mallctl*<parameter/></function> functions internally, so <function>mallctl*()</function> functions internally, so inconsistent
inconsistent statistics can be reported if multiple threads use these statistics can be reported if multiple threads use these functions
functions simultaneously. If <option>--enable-stats</option> is simultaneously. If <option>--enable-stats</option> is specified during
specified during configuration, &ldquo;m&rdquo; and &ldquo;a&rdquo; can configuration, <quote>m</quote> and <quote>a</quote> can be specified to
be specified to omit merged arena and per arena statistics, respectively; omit merged arena and per arena statistics, respectively;
&ldquo;b&rdquo;, &ldquo;l&rdquo;, and &ldquo;h&rdquo; can be specified to <quote>b</quote>, <quote>l</quote>, and <quote>h</quote> can be specified
omit per size class statistics for bins, large objects, and huge objects, to omit per size class statistics for bins, large objects, and huge
respectively. Unrecognized characters are silently ignored. Note that objects, respectively. Unrecognized characters are silently ignored.
thread caching may prevent some statistics from being completely up to Note that thread caching may prevent some statistics from being completely
date, since extra locking would be required to merge counters that track up to date, since extra locking would be required to merge counters that
thread cache operations. track thread cache operations.</para>
</para>
<para>The <function>malloc_usable_size<parameter/></function> function <para>The <function>malloc_usable_size()</function> function
returns the usable size of the allocation pointed to by returns the usable size of the allocation pointed to by
<parameter>ptr</parameter>. The return value may be larger than the size <parameter>ptr</parameter>. The return value may be larger than the size
that was requested during allocation. The that was requested during allocation. The
<function>malloc_usable_size<parameter/></function> function is not a <function>malloc_usable_size()</function> function is not a
mechanism for in-place <function>realloc<parameter/></function>; rather mechanism for in-place <function>realloc()</function>; rather
it is provided solely as a tool for introspection purposes. Any it is provided solely as a tool for introspection purposes. Any
discrepancy between the requested allocation size and the size reported discrepancy between the requested allocation size and the size reported
by <function>malloc_usable_size<parameter/></function> should not be by <function>malloc_usable_size()</function> should not be
depended on, since such behavior is entirely implementation-dependent. depended on, since such behavior is entirely implementation-dependent.
</para> </para>
</refsect2> </refsect2>
@@ -455,12 +456,12 @@ for (i = 0; i < nbins; i++) {
<para>The string specified via <option>--with-malloc-conf</option>, the <para>The string specified via <option>--with-malloc-conf</option>, the
string pointed to by the global variable <varname>malloc_conf</varname>, the string pointed to by the global variable <varname>malloc_conf</varname>, the
&ldquo;name&rdquo; of the file referenced by the symbolic link named <quote>name</quote> of the file referenced by the symbolic link named
<filename class="symlink">/etc/malloc.conf</filename>, and the value of the <filename class="symlink">/etc/malloc.conf</filename>, and the value of the
environment variable <envar>MALLOC_CONF</envar>, will be interpreted, in environment variable <envar>MALLOC_CONF</envar>, will be interpreted, in
that order, from left to right as options. Note that that order, from left to right as options. Note that
<varname>malloc_conf</varname> may be read before <varname>malloc_conf</varname> may be read before
<function>main<parameter/></function> is entered, so the declaration of <function>main()</function> is entered, so the declaration of
<varname>malloc_conf</varname> should specify an initializer that contains <varname>malloc_conf</varname> should specify an initializer that contains
the final value to be read by jemalloc. <option>--with-malloc-conf</option> the final value to be read by jemalloc. <option>--with-malloc-conf</option>
and <varname>malloc_conf</varname> are compile-time mechanisms, whereas and <varname>malloc_conf</varname> are compile-time mechanisms, whereas
@@ -549,14 +550,14 @@ for (i = 0; i < nbins; i++) {
nearest multiple of the cacheline size, or specify cacheline alignment when nearest multiple of the cacheline size, or specify cacheline alignment when
allocating.</para> allocating.</para>
<para>The <function>realloc<parameter/></function>, <para>The <function>realloc()</function>,
<function>rallocx<parameter/></function>, and <function>rallocx()</function>, and
<function>xallocx<parameter/></function> functions may resize allocations <function>xallocx()</function> functions may resize allocations
without moving them under limited circumstances. Unlike the without moving them under limited circumstances. Unlike the
<function>*allocx<parameter/></function> API, the standard API does not <function>*allocx()</function> API, the standard API does not
officially round up the usable size of an allocation to the nearest size officially round up the usable size of an allocation to the nearest size
class, so technically it is necessary to call class, so technically it is necessary to call
<function>realloc<parameter/></function> to grow e.g. a 9-byte allocation to <function>realloc()</function> to grow e.g. a 9-byte allocation to
16 bytes, or shrink a 16-byte allocation to 9 bytes. Growth and shrinkage 16 bytes, or shrink a 16-byte allocation to 9 bytes. Growth and shrinkage
trivially succeeds in place as long as the pre-size and post-size both round trivially succeeds in place as long as the pre-size and post-size both round
up to the same size class. No other API guarantees are made regarding up to the same size class. No other API guarantees are made regarding
@@ -702,7 +703,7 @@ for (i = 0; i < nbins; i++) {
<refsect1 id="mallctl_namespace"> <refsect1 id="mallctl_namespace">
<title>MALLCTL NAMESPACE</title> <title>MALLCTL NAMESPACE</title>
<para>The following names are defined in the namespace accessible via the <para>The following names are defined in the namespace accessible via the
<function>mallctl*<parameter/></function> functions. Value types are <function>mallctl*()</function> functions. Value types are
specified in parentheses, their readable/writable statuses are encoded as specified in parentheses, their readable/writable statuses are encoded as
<literal>rw</literal>, <literal>r-</literal>, <literal>-w</literal>, or <literal>rw</literal>, <literal>r-</literal>, <literal>-w</literal>, or
<literal>--</literal>, and required build configuration flags follow, if <literal>--</literal>, and required build configuration flags follow, if
@@ -733,7 +734,7 @@ for (i = 0; i < nbins; i++) {
<literal>rw</literal> <literal>rw</literal>
</term> </term>
<listitem><para>If a value is passed in, refresh the data from which <listitem><para>If a value is passed in, refresh the data from which
the <function>mallctl*<parameter/></function> functions report values, the <function>mallctl*()</function> functions report values,
and increment the epoch. Return the current epoch. This is useful for and increment the epoch. Return the current epoch. This is useful for
detecting whether another thread caused a refresh.</para></listitem> detecting whether another thread caused a refresh.</para></listitem>
</varlistentry> </varlistentry>
@@ -849,6 +850,17 @@ for (i = 0; i < nbins; i++) {
during build configuration.</para></listitem> during build configuration.</para></listitem>
</varlistentry> </varlistentry>
<varlistentry id="config.thp">
<term>
<mallctl>config.thp</mallctl>
(<type>bool</type>)
<literal>r-</literal>
</term>
<listitem><para><option>--disable-thp</option> was not specified
during build configuration, and the system supports transparent huge
page manipulation.</para></listitem>
</varlistentry>
<varlistentry id="config.tls"> <varlistentry id="config.tls">
<term> <term>
<mallctl>config.tls</mallctl> <mallctl>config.tls</mallctl>
@@ -917,12 +929,12 @@ for (i = 0; i < nbins; i++) {
settings are supported if settings are supported if
<citerefentry><refentrytitle>sbrk</refentrytitle> <citerefentry><refentrytitle>sbrk</refentrytitle>
<manvolnum>2</manvolnum></citerefentry> is supported by the operating <manvolnum>2</manvolnum></citerefentry> is supported by the operating
system: &ldquo;disabled&rdquo;, &ldquo;primary&rdquo;, and system: <quote>disabled</quote>, <quote>primary</quote>, and
&ldquo;secondary&rdquo;; otherwise only &ldquo;disabled&rdquo; is <quote>secondary</quote>; otherwise only <quote>disabled</quote> is
supported. The default is &ldquo;secondary&rdquo; if supported. The default is <quote>secondary</quote> if
<citerefentry><refentrytitle>sbrk</refentrytitle> <citerefentry><refentrytitle>sbrk</refentrytitle>
<manvolnum>2</manvolnum></citerefentry> is supported by the operating <manvolnum>2</manvolnum></citerefentry> is supported by the operating
system; &ldquo;disabled&rdquo; otherwise. system; <quote>disabled</quote> otherwise.
</para></listitem> </para></listitem>
</varlistentry> </varlistentry>
@@ -1013,19 +1025,19 @@ for (i = 0; i < nbins; i++) {
<literal>r-</literal> <literal>r-</literal>
</term> </term>
<listitem><para>Enable/disable statistics printing at exit. If <listitem><para>Enable/disable statistics printing at exit. If
enabled, the <function>malloc_stats_print<parameter/></function> enabled, the <function>malloc_stats_print()</function>
function is called at program exit via an function is called at program exit via an
<citerefentry><refentrytitle>atexit</refentrytitle> <citerefentry><refentrytitle>atexit</refentrytitle>
<manvolnum>3</manvolnum></citerefentry> function. If <manvolnum>3</manvolnum></citerefentry> function. If
<option>--enable-stats</option> is specified during configuration, this <option>--enable-stats</option> is specified during configuration, this
has the potential to cause deadlock for a multi-threaded process that has the potential to cause deadlock for a multi-threaded process that
exits while one or more threads are executing in the memory allocation exits while one or more threads are executing in the memory allocation
functions. Furthermore, <function>atexit<parameter/></function> may functions. Furthermore, <function>atexit()</function> may
allocate memory during application initialization and then deadlock allocate memory during application initialization and then deadlock
internally when jemalloc in turn calls internally when jemalloc in turn calls
<function>atexit<parameter/></function>, so this option is not <function>atexit()</function>, so this option is not
universally usable (though the application can register its own universally usable (though the application can register its own
<function>atexit<parameter/></function> function with equivalent <function>atexit()</function> function with equivalent
functionality). Therefore, this option should only be used with care; functionality). Therefore, this option should only be used with care;
it is primarily intended as a performance tuning aid during application it is primarily intended as a performance tuning aid during application
development. This option is disabled by default.</para></listitem> development. This option is disabled by default.</para></listitem>
@@ -1038,15 +1050,16 @@ for (i = 0; i < nbins; i++) {
<literal>r-</literal> <literal>r-</literal>
[<option>--enable-fill</option>] [<option>--enable-fill</option>]
</term> </term>
<listitem><para>Junk filling. If set to "alloc", each byte of <listitem><para>Junk filling. If set to <quote>alloc</quote>, each byte
uninitialized allocated memory will be initialized to of uninitialized allocated memory will be initialized to
<literal>0xa5</literal>. If set to "free", all deallocated memory will <literal>0xa5</literal>. If set to <quote>free</quote>, all deallocated
be initialized to <literal>0x5a</literal>. If set to "true", both memory will be initialized to <literal>0x5a</literal>. If set to
allocated and deallocated memory will be initialized, and if set to <quote>true</quote>, both allocated and deallocated memory will be
"false", junk filling be disabled entirely. This is intended for initialized, and if set to <quote>false</quote>, junk filling be
debugging and will impact performance negatively. This option is disabled entirely. This is intended for debugging and will impact
"false" by default unless <option>--enable-debug</option> is specified performance negatively. This option is <quote>false</quote> by default
during configuration, in which case it is "true" by default unless unless <option>--enable-debug</option> is specified during
configuration, in which case it is <quote>true</quote> by default unless
running inside <ulink running inside <ulink
url="http://valgrind.org/">Valgrind</ulink>.</para></listitem> url="http://valgrind.org/">Valgrind</ulink>.</para></listitem>
</varlistentry> </varlistentry>
@@ -1101,8 +1114,8 @@ for (i = 0; i < nbins; i++) {
<listitem><para>Zero filling enabled/disabled. If enabled, each byte <listitem><para>Zero filling enabled/disabled. If enabled, each byte
of uninitialized allocated memory will be initialized to 0. Note that of uninitialized allocated memory will be initialized to 0. Note that
this initialization only happens once for each byte, so this initialization only happens once for each byte, so
<function>realloc<parameter/></function> and <function>realloc()</function> and
<function>rallocx<parameter/></function> calls do not zero memory that <function>rallocx()</function> calls do not zero memory that
was previously allocated. This is intended for debugging and will was previously allocated. This is intended for debugging and will
impact performance negatively. This option is disabled by default. impact performance negatively. This option is disabled by default.
</para></listitem> </para></listitem>
@@ -1160,6 +1173,21 @@ malloc_conf = "xmalloc:true";]]></programlisting>
forcefully disabled.</para></listitem> forcefully disabled.</para></listitem>
</varlistentry> </varlistentry>
<varlistentry id="opt.thp">
<term>
<mallctl>opt.thp</mallctl>
(<type>bool</type>)
<literal>r-</literal>
[<option>--enable-thp</option>]
</term>
<listitem><para>Transparent huge page (THP) integration
enabled/disabled. When enabled, THPs are explicitly disabled as a side
effect of unused dirty page purging for chunks that back small and/or
large allocations, because such chunks typically comprise active,
unused dirty, and untouched clean pages. This option is enabled by
default.</para></listitem>
</varlistentry>
<varlistentry id="opt.lg_tcache_max"> <varlistentry id="opt.lg_tcache_max">
<term> <term>
<mallctl>opt.lg_tcache_max</mallctl> <mallctl>opt.lg_tcache_max</mallctl>
@@ -1325,11 +1353,11 @@ malloc_conf = "xmalloc:true";]]></programlisting>
<filename>&lt;prefix&gt;.&lt;pid&gt;.&lt;seq&gt;.f.heap</filename>, <filename>&lt;prefix&gt;.&lt;pid&gt;.&lt;seq&gt;.f.heap</filename>,
where <literal>&lt;prefix&gt;</literal> is controlled by the <link where <literal>&lt;prefix&gt;</literal> is controlled by the <link
linkend="opt.prof_prefix"><mallctl>opt.prof_prefix</mallctl></link> linkend="opt.prof_prefix"><mallctl>opt.prof_prefix</mallctl></link>
option. Note that <function>atexit<parameter/></function> may allocate option. Note that <function>atexit()</function> may allocate
memory during application initialization and then deadlock internally memory during application initialization and then deadlock internally
when jemalloc in turn calls <function>atexit<parameter/></function>, so when jemalloc in turn calls <function>atexit()</function>, so
this option is not universally usable (though the application can this option is not universally usable (though the application can
register its own <function>atexit<parameter/></function> function with register its own <function>atexit()</function> function with
equivalent functionality). This option is disabled by equivalent functionality). This option is disabled by
default.</para></listitem> default.</para></listitem>
</varlistentry> </varlistentry>
@@ -1388,7 +1416,7 @@ malloc_conf = "xmalloc:true";]]></programlisting>
<link <link
linkend="thread.allocated"><mallctl>thread.allocated</mallctl></link> linkend="thread.allocated"><mallctl>thread.allocated</mallctl></link>
mallctl. This is useful for avoiding the overhead of repeated mallctl. This is useful for avoiding the overhead of repeated
<function>mallctl*<parameter/></function> calls.</para></listitem> <function>mallctl*()</function> calls.</para></listitem>
</varlistentry> </varlistentry>
<varlistentry id="thread.deallocated"> <varlistentry id="thread.deallocated">
@@ -1415,7 +1443,7 @@ malloc_conf = "xmalloc:true";]]></programlisting>
<link <link
linkend="thread.deallocated"><mallctl>thread.deallocated</mallctl></link> linkend="thread.deallocated"><mallctl>thread.deallocated</mallctl></link>
mallctl. This is useful for avoiding the overhead of repeated mallctl. This is useful for avoiding the overhead of repeated
<function>mallctl*<parameter/></function> calls.</para></listitem> <function>mallctl*()</function> calls.</para></listitem>
</varlistentry> </varlistentry>
<varlistentry id="thread.tcache.enabled"> <varlistentry id="thread.tcache.enabled">
@@ -2734,7 +2762,7 @@ MAPPED_LIBRARIES:
of run-time assertions that catch application errors such as double-free, of run-time assertions that catch application errors such as double-free,
write-after-free, etc.</para> write-after-free, etc.</para>
<para>Programs often accidentally depend on &ldquo;uninitialized&rdquo; <para>Programs often accidentally depend on <quote>uninitialized</quote>
memory actually being filled with zero bytes. Junk filling memory actually being filled with zero bytes. Junk filling
(see the <link linkend="opt.junk"><mallctl>opt.junk</mallctl></link> (see the <link linkend="opt.junk"><mallctl>opt.junk</mallctl></link>
option) tends to expose such bugs in the form of obviously incorrect option) tends to expose such bugs in the form of obviously incorrect
@@ -2763,29 +2791,29 @@ MAPPED_LIBRARIES:
to override the function which emits the text strings forming the errors to override the function which emits the text strings forming the errors
and warnings if for some reason the <constant>STDERR_FILENO</constant> file and warnings if for some reason the <constant>STDERR_FILENO</constant> file
descriptor is not suitable for this. descriptor is not suitable for this.
<function>malloc_message<parameter/></function> takes the <function>malloc_message()</function> takes the
<parameter>cbopaque</parameter> pointer argument that is <parameter>cbopaque</parameter> pointer argument that is
<constant>NULL</constant> unless overridden by the arguments in a call to <constant>NULL</constant> unless overridden by the arguments in a call to
<function>malloc_stats_print<parameter/></function>, followed by a string <function>malloc_stats_print()</function>, followed by a string
pointer. Please note that doing anything which tries to allocate memory in pointer. Please note that doing anything which tries to allocate memory in
this function is likely to result in a crash or deadlock.</para> this function is likely to result in a crash or deadlock.</para>
<para>All messages are prefixed by <para>All messages are prefixed by
&ldquo;<computeroutput>&lt;jemalloc&gt;: </computeroutput>&rdquo;.</para> <quote><computeroutput>&lt;jemalloc&gt;: </computeroutput></quote>.</para>
</refsect1> </refsect1>
<refsect1 id="return_values"> <refsect1 id="return_values">
<title>RETURN VALUES</title> <title>RETURN VALUES</title>
<refsect2> <refsect2>
<title>Standard API</title> <title>Standard API</title>
<para>The <function>malloc<parameter/></function> and <para>The <function>malloc()</function> and
<function>calloc<parameter/></function> functions return a pointer to the <function>calloc()</function> functions return a pointer to the
allocated memory if successful; otherwise a <constant>NULL</constant> allocated memory if successful; otherwise a <constant>NULL</constant>
pointer is returned and <varname>errno</varname> is set to pointer is returned and <varname>errno</varname> is set to
<errorname>ENOMEM</errorname>.</para> <errorname>ENOMEM</errorname>.</para>
<para>The <function>posix_memalign<parameter/></function> function <para>The <function>posix_memalign()</function> function
returns the value 0 if successful; otherwise it returns an error value. returns the value 0 if successful; otherwise it returns an error value.
The <function>posix_memalign<parameter/></function> function will fail The <function>posix_memalign()</function> function will fail
if: if:
<variablelist> <variablelist>
<varlistentry> <varlistentry>
@@ -2804,11 +2832,11 @@ MAPPED_LIBRARIES:
</variablelist> </variablelist>
</para> </para>
<para>The <function>aligned_alloc<parameter/></function> function returns <para>The <function>aligned_alloc()</function> function returns
a pointer to the allocated memory if successful; otherwise a a pointer to the allocated memory if successful; otherwise a
<constant>NULL</constant> pointer is returned and <constant>NULL</constant> pointer is returned and
<varname>errno</varname> is set. The <varname>errno</varname> is set. The
<function>aligned_alloc<parameter/></function> function will fail if: <function>aligned_alloc()</function> function will fail if:
<variablelist> <variablelist>
<varlistentry> <varlistentry>
<term><errorname>EINVAL</errorname></term> <term><errorname>EINVAL</errorname></term>
@@ -2825,44 +2853,44 @@ MAPPED_LIBRARIES:
</variablelist> </variablelist>
</para> </para>
<para>The <function>realloc<parameter/></function> function returns a <para>The <function>realloc()</function> function returns a
pointer, possibly identical to <parameter>ptr</parameter>, to the pointer, possibly identical to <parameter>ptr</parameter>, to the
allocated memory if successful; otherwise a <constant>NULL</constant> allocated memory if successful; otherwise a <constant>NULL</constant>
pointer is returned, and <varname>errno</varname> is set to pointer is returned, and <varname>errno</varname> is set to
<errorname>ENOMEM</errorname> if the error was the result of an <errorname>ENOMEM</errorname> if the error was the result of an
allocation failure. The <function>realloc<parameter/></function> allocation failure. The <function>realloc()</function>
function always leaves the original buffer intact when an error occurs. function always leaves the original buffer intact when an error occurs.
</para> </para>
<para>The <function>free<parameter/></function> function returns no <para>The <function>free()</function> function returns no
value.</para> value.</para>
</refsect2> </refsect2>
<refsect2> <refsect2>
<title>Non-standard API</title> <title>Non-standard API</title>
<para>The <function>mallocx<parameter/></function> and <para>The <function>mallocx()</function> and
<function>rallocx<parameter/></function> functions return a pointer to <function>rallocx()</function> functions return a pointer to
the allocated memory if successful; otherwise a <constant>NULL</constant> the allocated memory if successful; otherwise a <constant>NULL</constant>
pointer is returned to indicate insufficient contiguous memory was pointer is returned to indicate insufficient contiguous memory was
available to service the allocation request. </para> available to service the allocation request. </para>
<para>The <function>xallocx<parameter/></function> function returns the <para>The <function>xallocx()</function> function returns the
real size of the resulting resized allocation pointed to by real size of the resulting resized allocation pointed to by
<parameter>ptr</parameter>, which is a value less than <parameter>ptr</parameter>, which is a value less than
<parameter>size</parameter> if the allocation could not be adequately <parameter>size</parameter> if the allocation could not be adequately
grown in place. </para> grown in place. </para>
<para>The <function>sallocx<parameter/></function> function returns the <para>The <function>sallocx()</function> function returns the
real size of the allocation pointed to by <parameter>ptr</parameter>. real size of the allocation pointed to by <parameter>ptr</parameter>.
</para> </para>
<para>The <function>nallocx<parameter/></function> returns the real size <para>The <function>nallocx()</function> returns the real size
that would result from a successful equivalent that would result from a successful equivalent
<function>mallocx<parameter/></function> function call, or zero if <function>mallocx()</function> function call, or zero if
insufficient memory is available to perform the size computation. </para> insufficient memory is available to perform the size computation. </para>
<para>The <function>mallctl<parameter/></function>, <para>The <function>mallctl()</function>,
<function>mallctlnametomib<parameter/></function>, and <function>mallctlnametomib()</function>, and
<function>mallctlbymib<parameter/></function> functions return 0 on <function>mallctlbymib()</function> functions return 0 on
success; otherwise they return an error value. The functions will fail success; otherwise they return an error value. The functions will fail
if: if:
<variablelist> <variablelist>
@@ -2898,13 +2926,13 @@ MAPPED_LIBRARIES:
<term><errorname>EFAULT</errorname></term> <term><errorname>EFAULT</errorname></term>
<listitem><para>An interface with side effects failed in some way <listitem><para>An interface with side effects failed in some way
not directly related to <function>mallctl*<parameter/></function> not directly related to <function>mallctl*()</function>
read/write processing.</para></listitem> read/write processing.</para></listitem>
</varlistentry> </varlistentry>
</variablelist> </variablelist>
</para> </para>
<para>The <function>malloc_usable_size<parameter/></function> function <para>The <function>malloc_usable_size()</function> function
returns the usable size of the allocation pointed to by returns the usable size of the allocation pointed to by
<parameter>ptr</parameter>. </para> <parameter>ptr</parameter>. </para>
</refsect2> </refsect2>
@@ -2952,13 +2980,13 @@ malloc_conf = "lg_chunk:24";]]></programlisting></para>
</refsect1> </refsect1>
<refsect1 id="standards"> <refsect1 id="standards">
<title>STANDARDS</title> <title>STANDARDS</title>
<para>The <function>malloc<parameter/></function>, <para>The <function>malloc()</function>,
<function>calloc<parameter/></function>, <function>calloc()</function>,
<function>realloc<parameter/></function>, and <function>realloc()</function>, and
<function>free<parameter/></function> functions conform to ISO/IEC <function>free()</function> functions conform to ISO/IEC
9899:1990 (&ldquo;ISO C90&rdquo;).</para> 9899:1990 (<quote>ISO C90</quote>).</para>
<para>The <function>posix_memalign<parameter/></function> function conforms <para>The <function>posix_memalign()</function> function conforms
to IEEE Std 1003.1-2001 (&ldquo;POSIX.1&rdquo;).</para> to IEEE Std 1003.1-2001 (<quote>POSIX.1</quote>).</para>
</refsect1> </refsect1>
</refentry> </refentry>

View File

@@ -1,7 +1,10 @@
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"> <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:param name="funcsynopsis.style">ansi</xsl:param> <xsl:param name="funcsynopsis.style">ansi</xsl:param>
<xsl:param name="function.parens" select="1"/> <xsl:param name="function.parens" select="0"/>
<xsl:template match="function">
<xsl:call-template name="inline.monoseq"/>
</xsl:template>
<xsl:template match="mallctl"> <xsl:template match="mallctl">
"<xsl:call-template name="inline.monoseq"/>" <quote><xsl:call-template name="inline.monoseq"/></quote>
</xsl:template> </xsl:template>
</xsl:stylesheet> </xsl:stylesheet>

View File

@@ -42,6 +42,7 @@ typedef struct arena_chunk_map_bits_s arena_chunk_map_bits_t;
typedef struct arena_chunk_map_misc_s arena_chunk_map_misc_t; typedef struct arena_chunk_map_misc_s arena_chunk_map_misc_t;
typedef struct arena_chunk_s arena_chunk_t; typedef struct arena_chunk_s arena_chunk_t;
typedef struct arena_bin_info_s arena_bin_info_t; typedef struct arena_bin_info_s arena_bin_info_t;
typedef struct arena_decay_s arena_decay_t;
typedef struct arena_bin_s arena_bin_t; typedef struct arena_bin_s arena_bin_t;
typedef struct arena_s arena_t; typedef struct arena_s arena_t;
typedef struct arena_tdata_s arena_tdata_t; typedef struct arena_tdata_s arena_tdata_t;
@@ -189,6 +190,14 @@ struct arena_chunk_s {
*/ */
extent_node_t node; extent_node_t node;
/*
* True if memory could be backed by transparent huge pages. This is
* only directly relevant to Linux, since it is the only supported
* platform on which jemalloc interacts with explicit transparent huge
* page controls.
*/
bool hugepage;
/* /*
* Map of pages within chunk that keeps track of free/large/small. The * Map of pages within chunk that keeps track of free/large/small. The
* first map_bias entries are omitted, since the chunk header does not * first map_bias entries are omitted, since the chunk header does not
@@ -257,6 +266,49 @@ struct arena_bin_info_s {
uint32_t reg0_offset; uint32_t reg0_offset;
}; };
struct arena_decay_s {
/*
* Approximate time in seconds from the creation of a set of unused
* dirty pages until an equivalent set of unused dirty pages is purged
* and/or reused.
*/
ssize_t time;
/* time / SMOOTHSTEP_NSTEPS. */
nstime_t interval;
/*
* Time at which the current decay interval logically started. We do
* not actually advance to a new epoch until sometime after it starts
* because of scheduling and computation delays, and it is even possible
* to completely skip epochs. In all cases, during epoch advancement we
* merge all relevant activity into the most recently recorded epoch.
*/
nstime_t epoch;
/* Deadline randomness generator. */
uint64_t jitter_state;
/*
* Deadline for current epoch. This is the sum of interval and per
* epoch jitter which is a uniform random variable in [0..interval).
* Epochs always advance by precise multiples of interval, but we
* randomize the deadline to reduce the likelihood of arenas purging in
* lockstep.
*/
nstime_t deadline;
/*
* Number of dirty pages at beginning of current epoch. During epoch
* advancement we use the delta between arena->decay.ndirty and
* arena->ndirty to determine how many dirty pages, if any, were
* generated.
*/
size_t ndirty;
/*
* Trailing log of how many unused dirty pages were generated during
* each of the past SMOOTHSTEP_NSTEPS decay epochs, where the last
* element is the most recent epoch. Corresponding epoch times are
* relative to epoch.
*/
size_t backlog[SMOOTHSTEP_NSTEPS];
};
struct arena_bin_s { struct arena_bin_s {
/* /*
* All operations on runcur, runs, and stats require that lock be * All operations on runcur, runs, and stats require that lock be
@@ -326,14 +378,16 @@ struct arena_s {
* PRNG state for cache index randomization of large allocation base * PRNG state for cache index randomization of large allocation base
* pointers. * pointers.
*/ */
uint64_t offset_state; size_t offset_state;
dss_prec_t dss_prec; dss_prec_t dss_prec;
/* Extant arena chunks. */ /* Extant arena chunks. */
ql_head(extent_node_t) achunks; ql_head(extent_node_t) achunks;
/* Extent serial number generator state. */
size_t extent_sn_next;
/* /*
* In order to avoid rapid chunk allocation/deallocation when an arena * In order to avoid rapid chunk allocation/deallocation when an arena
* oscillates right on the cusp of needing a new chunk, cache the most * oscillates right on the cusp of needing a new chunk, cache the most
@@ -394,52 +448,8 @@ struct arena_s {
arena_runs_dirty_link_t runs_dirty; arena_runs_dirty_link_t runs_dirty;
extent_node_t chunks_cache; extent_node_t chunks_cache;
/* /* Decay-based purging state. */
* Approximate time in seconds from the creation of a set of unused arena_decay_t decay;
* dirty pages until an equivalent set of unused dirty pages is purged
* and/or reused.
*/
ssize_t decay_time;
/* decay_time / SMOOTHSTEP_NSTEPS. */
nstime_t decay_interval;
/*
* Time at which the current decay interval logically started. We do
* not actually advance to a new epoch until sometime after it starts
* because of scheduling and computation delays, and it is even possible
* to completely skip epochs. In all cases, during epoch advancement we
* merge all relevant activity into the most recently recorded epoch.
*/
nstime_t decay_epoch;
/* decay_deadline randomness generator. */
uint64_t decay_jitter_state;
/*
* Deadline for current epoch. This is the sum of decay_interval and
* per epoch jitter which is a uniform random variable in
* [0..decay_interval). Epochs always advance by precise multiples of
* decay_interval, but we randomize the deadline to reduce the
* likelihood of arenas purging in lockstep.
*/
nstime_t decay_deadline;
/*
* Number of dirty pages at beginning of current epoch. During epoch
* advancement we use the delta between decay_ndirty and ndirty to
* determine how many dirty pages, if any, were generated, and record
* the result in decay_backlog.
*/
size_t decay_ndirty;
/*
* Memoized result of arena_decay_backlog_npages_limit() corresponding
* to the current contents of decay_backlog, i.e. the limit on how many
* pages are allowed to exist for the decay epochs.
*/
size_t decay_backlog_npages_limit;
/*
* Trailing log of how many unused dirty pages were generated during
* each of the past SMOOTHSTEP_NSTEPS decay epochs, where the last
* element is the most recent epoch. Corresponding epoch times are
* relative to decay_epoch.
*/
size_t decay_backlog[SMOOTHSTEP_NSTEPS];
/* Extant huge allocations. */ /* Extant huge allocations. */
ql_head(extent_node_t) huge; ql_head(extent_node_t) huge;
@@ -453,9 +463,9 @@ struct arena_s {
* orderings are needed, which is why there are two trees with the same * orderings are needed, which is why there are two trees with the same
* contents. * contents.
*/ */
extent_tree_t chunks_szad_cached; extent_tree_t chunks_szsnad_cached;
extent_tree_t chunks_ad_cached; extent_tree_t chunks_ad_cached;
extent_tree_t chunks_szad_retained; extent_tree_t chunks_szsnad_retained;
extent_tree_t chunks_ad_retained; extent_tree_t chunks_ad_retained;
malloc_mutex_t chunks_mtx; malloc_mutex_t chunks_mtx;
@@ -470,10 +480,12 @@ struct arena_s {
arena_bin_t bins[NBINS]; arena_bin_t bins[NBINS];
/* /*
* Quantized address-ordered heaps of this arena's available runs. The * Size-segregated address-ordered heaps of this arena's available runs,
* heaps are used for first-best-fit run allocation. * used for first-best-fit run allocation. Runs are quantized, i.e.
* they reside in the last heap which corresponds to a size class less
* than or equal to the run size.
*/ */
arena_run_heap_t runs_avail[1]; /* Dynamically sized. */ arena_run_heap_t runs_avail[NPSIZES];
}; };
/* Used in conjunction with tsd for fast arena-related context lookup. */ /* Used in conjunction with tsd for fast arena-related context lookup. */
@@ -494,6 +506,7 @@ static const size_t large_pad =
#endif #endif
; ;
extern bool opt_thp;
extern purge_mode_t opt_purge; extern purge_mode_t opt_purge;
extern const char *purge_mode_names[]; extern const char *purge_mode_names[];
extern ssize_t opt_lg_dirty_mult; extern ssize_t opt_lg_dirty_mult;
@@ -505,7 +518,6 @@ extern size_t map_bias; /* Number of arena chunk header pages. */
extern size_t map_misc_offset; extern size_t map_misc_offset;
extern size_t arena_maxrun; /* Max run size for arenas. */ extern size_t arena_maxrun; /* Max run size for arenas. */
extern size_t large_maxclass; /* Max large size class. */ extern size_t large_maxclass; /* Max large size class. */
extern size_t run_quantize_max; /* Max run_quantize_*() input. */
extern unsigned nlclasses; /* Number of large size classes. */ extern unsigned nlclasses; /* Number of large size classes. */
extern unsigned nhclasses; /* Number of huge size classes. */ extern unsigned nhclasses; /* Number of huge size classes. */
@@ -521,13 +533,13 @@ void arena_chunk_cache_maybe_remove(arena_t *arena, extent_node_t *node,
extent_node_t *arena_node_alloc(tsdn_t *tsdn, arena_t *arena); extent_node_t *arena_node_alloc(tsdn_t *tsdn, arena_t *arena);
void arena_node_dalloc(tsdn_t *tsdn, arena_t *arena, extent_node_t *node); void arena_node_dalloc(tsdn_t *tsdn, arena_t *arena, extent_node_t *node);
void *arena_chunk_alloc_huge(tsdn_t *tsdn, arena_t *arena, size_t usize, void *arena_chunk_alloc_huge(tsdn_t *tsdn, arena_t *arena, size_t usize,
size_t alignment, bool *zero); size_t alignment, size_t *sn, bool *zero);
void arena_chunk_dalloc_huge(tsdn_t *tsdn, arena_t *arena, void *chunk, void arena_chunk_dalloc_huge(tsdn_t *tsdn, arena_t *arena, void *chunk,
size_t usize); size_t usize, size_t sn);
void arena_chunk_ralloc_huge_similar(tsdn_t *tsdn, arena_t *arena, void arena_chunk_ralloc_huge_similar(tsdn_t *tsdn, arena_t *arena,
void *chunk, size_t oldsize, size_t usize); void *chunk, size_t oldsize, size_t usize);
void arena_chunk_ralloc_huge_shrink(tsdn_t *tsdn, arena_t *arena, void arena_chunk_ralloc_huge_shrink(tsdn_t *tsdn, arena_t *arena,
void *chunk, size_t oldsize, size_t usize); void *chunk, size_t oldsize, size_t usize, size_t sn);
bool arena_chunk_ralloc_huge_expand(tsdn_t *tsdn, arena_t *arena, bool arena_chunk_ralloc_huge_expand(tsdn_t *tsdn, arena_t *arena,
void *chunk, size_t oldsize, size_t usize, bool *zero); void *chunk, size_t oldsize, size_t usize, bool *zero);
ssize_t arena_lg_dirty_mult_get(tsdn_t *tsdn, arena_t *arena); ssize_t arena_lg_dirty_mult_get(tsdn_t *tsdn, arena_t *arena);
@@ -600,8 +612,9 @@ void arena_stats_merge(tsdn_t *tsdn, arena_t *arena, unsigned *nthreads,
unsigned arena_nthreads_get(arena_t *arena, bool internal); unsigned arena_nthreads_get(arena_t *arena, bool internal);
void arena_nthreads_inc(arena_t *arena, bool internal); void arena_nthreads_inc(arena_t *arena, bool internal);
void arena_nthreads_dec(arena_t *arena, bool internal); void arena_nthreads_dec(arena_t *arena, bool internal);
size_t arena_extent_sn_next(arena_t *arena);
arena_t *arena_new(tsdn_t *tsdn, unsigned ind); arena_t *arena_new(tsdn_t *tsdn, unsigned ind);
bool arena_boot(void); void arena_boot(void);
void arena_prefork0(tsdn_t *tsdn, arena_t *arena); void arena_prefork0(tsdn_t *tsdn, arena_t *arena);
void arena_prefork1(tsdn_t *tsdn, arena_t *arena); void arena_prefork1(tsdn_t *tsdn, arena_t *arena);
void arena_prefork2(tsdn_t *tsdn, arena_t *arena); void arena_prefork2(tsdn_t *tsdn, arena_t *arena);

View File

@@ -52,28 +52,26 @@ chunk_hooks_t chunk_hooks_get(tsdn_t *tsdn, arena_t *arena);
chunk_hooks_t chunk_hooks_set(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t chunk_hooks_set(tsdn_t *tsdn, arena_t *arena,
const chunk_hooks_t *chunk_hooks); const chunk_hooks_t *chunk_hooks);
bool chunk_register(tsdn_t *tsdn, const void *chunk, bool chunk_register(const void *chunk, const extent_node_t *node,
const extent_node_t *node); bool *gdump);
void chunk_deregister(const void *chunk, const extent_node_t *node); void chunk_deregister(const void *chunk, const extent_node_t *node);
void *chunk_alloc_base(size_t size); void *chunk_alloc_base(size_t size);
void *chunk_alloc_cache(tsdn_t *tsdn, arena_t *arena, void *chunk_alloc_cache(tsdn_t *tsdn, arena_t *arena,
chunk_hooks_t *chunk_hooks, void *new_addr, size_t size, size_t alignment, chunk_hooks_t *chunk_hooks, void *new_addr, size_t size, size_t alignment,
bool *zero, bool dalloc_node); size_t *sn, bool *zero, bool *commit, bool dalloc_node);
void *chunk_alloc_wrapper(tsdn_t *tsdn, arena_t *arena, void *chunk_alloc_wrapper(tsdn_t *tsdn, arena_t *arena,
chunk_hooks_t *chunk_hooks, void *new_addr, size_t size, size_t alignment, chunk_hooks_t *chunk_hooks, void *new_addr, size_t size, size_t alignment,
bool *zero, bool *commit); size_t *sn, bool *zero, bool *commit);
void chunk_dalloc_cache(tsdn_t *tsdn, arena_t *arena, void chunk_dalloc_cache(tsdn_t *tsdn, arena_t *arena,
chunk_hooks_t *chunk_hooks, void *chunk, size_t size, bool committed); chunk_hooks_t *chunk_hooks, void *chunk, size_t size, size_t sn,
void chunk_dalloc_wrapper(tsdn_t *tsdn, arena_t *arena,
chunk_hooks_t *chunk_hooks, void *chunk, size_t size, bool zeroed,
bool committed); bool committed);
void chunk_dalloc_wrapper(tsdn_t *tsdn, arena_t *arena,
chunk_hooks_t *chunk_hooks, void *chunk, size_t size, size_t sn,
bool zeroed, bool committed);
bool chunk_purge_wrapper(tsdn_t *tsdn, arena_t *arena, bool chunk_purge_wrapper(tsdn_t *tsdn, arena_t *arena,
chunk_hooks_t *chunk_hooks, void *chunk, size_t size, size_t offset, chunk_hooks_t *chunk_hooks, void *chunk, size_t size, size_t offset,
size_t length); size_t length);
bool chunk_boot(void); bool chunk_boot(void);
void chunk_prefork(tsdn_t *tsdn);
void chunk_postfork_parent(tsdn_t *tsdn);
void chunk_postfork_child(tsdn_t *tsdn);
#endif /* JEMALLOC_H_EXTERNS */ #endif /* JEMALLOC_H_EXTERNS */
/******************************************************************************/ /******************************************************************************/

View File

@@ -21,15 +21,13 @@ extern const char *dss_prec_names[];
/******************************************************************************/ /******************************************************************************/
#ifdef JEMALLOC_H_EXTERNS #ifdef JEMALLOC_H_EXTERNS
dss_prec_t chunk_dss_prec_get(tsdn_t *tsdn); dss_prec_t chunk_dss_prec_get(void);
bool chunk_dss_prec_set(tsdn_t *tsdn, dss_prec_t dss_prec); bool chunk_dss_prec_set(dss_prec_t dss_prec);
void *chunk_alloc_dss(tsdn_t *tsdn, arena_t *arena, void *new_addr, void *chunk_alloc_dss(tsdn_t *tsdn, arena_t *arena, void *new_addr,
size_t size, size_t alignment, bool *zero, bool *commit); size_t size, size_t alignment, bool *zero, bool *commit);
bool chunk_in_dss(tsdn_t *tsdn, void *chunk); bool chunk_in_dss(void *chunk);
bool chunk_dss_boot(void); bool chunk_dss_mergeable(void *chunk_a, void *chunk_b);
void chunk_dss_prefork(tsdn_t *tsdn); void chunk_dss_boot(void);
void chunk_dss_postfork_parent(tsdn_t *tsdn);
void chunk_dss_postfork_child(tsdn_t *tsdn);
#endif /* JEMALLOC_H_EXTERNS */ #endif /* JEMALLOC_H_EXTERNS */
/******************************************************************************/ /******************************************************************************/

View File

@@ -64,13 +64,13 @@ struct ckh_s {
/******************************************************************************/ /******************************************************************************/
#ifdef JEMALLOC_H_EXTERNS #ifdef JEMALLOC_H_EXTERNS
bool ckh_new(tsdn_t *tsdn, ckh_t *ckh, size_t minitems, ckh_hash_t *hash, bool ckh_new(tsd_t *tsd, ckh_t *ckh, size_t minitems, ckh_hash_t *hash,
ckh_keycomp_t *keycomp); ckh_keycomp_t *keycomp);
void ckh_delete(tsdn_t *tsdn, ckh_t *ckh); void ckh_delete(tsd_t *tsd, ckh_t *ckh);
size_t ckh_count(ckh_t *ckh); size_t ckh_count(ckh_t *ckh);
bool ckh_iter(ckh_t *ckh, size_t *tabind, void **key, void **data); bool ckh_iter(ckh_t *ckh, size_t *tabind, void **key, void **data);
bool ckh_insert(tsdn_t *tsdn, ckh_t *ckh, const void *key, const void *data); bool ckh_insert(tsd_t *tsd, ckh_t *ckh, const void *key, const void *data);
bool ckh_remove(tsdn_t *tsdn, ckh_t *ckh, const void *searchkey, void **key, bool ckh_remove(tsd_t *tsd, ckh_t *ckh, const void *searchkey, void **key,
void **data); void **data);
bool ckh_search(ckh_t *ckh, const void *searchkey, void **key, void **data); bool ckh_search(ckh_t *ckh, const void *searchkey, void **key, void **data);
void ckh_string_hash(const void *key, size_t r_hash[2]); void ckh_string_hash(const void *key, size_t r_hash[2]);

View File

@@ -18,6 +18,20 @@ struct extent_node_s {
/* Total region size. */ /* Total region size. */
size_t en_size; size_t en_size;
/*
* Serial number (potentially non-unique).
*
* In principle serial numbers can wrap around on 32-bit systems if
* JEMALLOC_MUNMAP is defined, but as long as comparison functions fall
* back on address comparison for equal serial numbers, stable (if
* imperfect) ordering is maintained.
*
* Serial numbers may not be unique even in the absence of wrap-around,
* e.g. when splitting an extent and assigning the same serial number to
* both resulting adjacent extents.
*/
size_t en_sn;
/* /*
* The zeroed flag is used by chunk recycling code to track whether * The zeroed flag is used by chunk recycling code to track whether
* memory is zero-filled. * memory is zero-filled.
@@ -45,8 +59,8 @@ struct extent_node_s {
qr(extent_node_t) cc_link; qr(extent_node_t) cc_link;
union { union {
/* Linkage for the size/address-ordered tree. */ /* Linkage for the size/sn/address-ordered tree. */
rb_node(extent_node_t) szad_link; rb_node(extent_node_t) szsnad_link;
/* Linkage for arena's achunks, huge, and node_cache lists. */ /* Linkage for arena's achunks, huge, and node_cache lists. */
ql_elm(extent_node_t) ql_link; ql_elm(extent_node_t) ql_link;
@@ -61,7 +75,12 @@ typedef rb_tree(extent_node_t) extent_tree_t;
/******************************************************************************/ /******************************************************************************/
#ifdef JEMALLOC_H_EXTERNS #ifdef JEMALLOC_H_EXTERNS
rb_proto(, extent_tree_szad_, extent_tree_t, extent_node_t) #ifdef JEMALLOC_JET
size_t extent_size_quantize_floor(size_t size);
#endif
size_t extent_size_quantize_ceil(size_t size);
rb_proto(, extent_tree_szsnad_, extent_tree_t, extent_node_t)
rb_proto(, extent_tree_ad_, extent_tree_t, extent_node_t) rb_proto(, extent_tree_ad_, extent_tree_t, extent_node_t)
@@ -73,6 +92,7 @@ rb_proto(, extent_tree_ad_, extent_tree_t, extent_node_t)
arena_t *extent_node_arena_get(const extent_node_t *node); arena_t *extent_node_arena_get(const extent_node_t *node);
void *extent_node_addr_get(const extent_node_t *node); void *extent_node_addr_get(const extent_node_t *node);
size_t extent_node_size_get(const extent_node_t *node); size_t extent_node_size_get(const extent_node_t *node);
size_t extent_node_sn_get(const extent_node_t *node);
bool extent_node_zeroed_get(const extent_node_t *node); bool extent_node_zeroed_get(const extent_node_t *node);
bool extent_node_committed_get(const extent_node_t *node); bool extent_node_committed_get(const extent_node_t *node);
bool extent_node_achunk_get(const extent_node_t *node); bool extent_node_achunk_get(const extent_node_t *node);
@@ -80,12 +100,13 @@ prof_tctx_t *extent_node_prof_tctx_get(const extent_node_t *node);
void extent_node_arena_set(extent_node_t *node, arena_t *arena); void extent_node_arena_set(extent_node_t *node, arena_t *arena);
void extent_node_addr_set(extent_node_t *node, void *addr); void extent_node_addr_set(extent_node_t *node, void *addr);
void extent_node_size_set(extent_node_t *node, size_t size); void extent_node_size_set(extent_node_t *node, size_t size);
void extent_node_sn_set(extent_node_t *node, size_t sn);
void extent_node_zeroed_set(extent_node_t *node, bool zeroed); void extent_node_zeroed_set(extent_node_t *node, bool zeroed);
void extent_node_committed_set(extent_node_t *node, bool committed); void extent_node_committed_set(extent_node_t *node, bool committed);
void extent_node_achunk_set(extent_node_t *node, bool achunk); void extent_node_achunk_set(extent_node_t *node, bool achunk);
void extent_node_prof_tctx_set(extent_node_t *node, prof_tctx_t *tctx); void extent_node_prof_tctx_set(extent_node_t *node, prof_tctx_t *tctx);
void extent_node_init(extent_node_t *node, arena_t *arena, void *addr, void extent_node_init(extent_node_t *node, arena_t *arena, void *addr,
size_t size, bool zeroed, bool committed); size_t size, size_t sn, bool zeroed, bool committed);
void extent_node_dirty_linkage_init(extent_node_t *node); void extent_node_dirty_linkage_init(extent_node_t *node);
void extent_node_dirty_insert(extent_node_t *node, void extent_node_dirty_insert(extent_node_t *node,
arena_runs_dirty_link_t *runs_dirty, extent_node_t *chunks_dirty); arena_runs_dirty_link_t *runs_dirty, extent_node_t *chunks_dirty);
@@ -114,6 +135,13 @@ extent_node_size_get(const extent_node_t *node)
return (node->en_size); return (node->en_size);
} }
JEMALLOC_INLINE size_t
extent_node_sn_get(const extent_node_t *node)
{
return (node->en_sn);
}
JEMALLOC_INLINE bool JEMALLOC_INLINE bool
extent_node_zeroed_get(const extent_node_t *node) extent_node_zeroed_get(const extent_node_t *node)
{ {
@@ -164,6 +192,13 @@ extent_node_size_set(extent_node_t *node, size_t size)
node->en_size = size; node->en_size = size;
} }
JEMALLOC_INLINE void
extent_node_sn_set(extent_node_t *node, size_t sn)
{
node->en_sn = sn;
}
JEMALLOC_INLINE void JEMALLOC_INLINE void
extent_node_zeroed_set(extent_node_t *node, bool zeroed) extent_node_zeroed_set(extent_node_t *node, bool zeroed)
{ {
@@ -194,12 +229,13 @@ extent_node_prof_tctx_set(extent_node_t *node, prof_tctx_t *tctx)
JEMALLOC_INLINE void JEMALLOC_INLINE void
extent_node_init(extent_node_t *node, arena_t *arena, void *addr, size_t size, extent_node_init(extent_node_t *node, arena_t *arena, void *addr, size_t size,
bool zeroed, bool committed) size_t sn, bool zeroed, bool committed)
{ {
extent_node_arena_set(node, arena); extent_node_arena_set(node, arena);
extent_node_addr_set(node, addr); extent_node_addr_set(node, addr);
extent_node_size_set(node, size); extent_node_size_set(node, size);
extent_node_sn_set(node, sn);
extent_node_zeroed_set(node, zeroed); extent_node_zeroed_set(node, zeroed);
extent_node_committed_set(node, committed); extent_node_committed_set(node, committed);
extent_node_achunk_set(node, false); extent_node_achunk_set(node, false);

View File

@@ -17,7 +17,7 @@ bool huge_ralloc_no_move(tsdn_t *tsdn, void *ptr, size_t oldsize,
void *huge_ralloc(tsd_t *tsd, arena_t *arena, void *ptr, size_t oldsize, void *huge_ralloc(tsd_t *tsd, arena_t *arena, void *ptr, size_t oldsize,
size_t usize, size_t alignment, bool zero, tcache_t *tcache); size_t usize, size_t alignment, bool zero, tcache_t *tcache);
#ifdef JEMALLOC_JET #ifdef JEMALLOC_JET
typedef void (huge_dalloc_junk_t)(tsdn_t *, void *, size_t); typedef void (huge_dalloc_junk_t)(void *, size_t);
extern huge_dalloc_junk_t *huge_dalloc_junk; extern huge_dalloc_junk_t *huge_dalloc_junk;
#endif #endif
void huge_dalloc(tsdn_t *tsdn, void *ptr); void huge_dalloc(tsdn_t *tsdn, void *ptr);

View File

@@ -99,6 +99,13 @@ static const bool config_tcache =
false false
#endif #endif
; ;
static const bool config_thp =
#ifdef JEMALLOC_THP
true
#else
false
#endif
;
static const bool config_tls = static const bool config_tls =
#ifdef JEMALLOC_TLS #ifdef JEMALLOC_TLS
true true
@@ -158,11 +165,12 @@ static const bool config_cache_oblivious =
#include <mach/mach_error.h> #include <mach/mach_error.h>
#include <mach/mach_init.h> #include <mach/mach_init.h>
#include <mach/vm_map.h> #include <mach/vm_map.h>
#include <malloc/malloc.h>
#endif #endif
#include "jemalloc/internal/ph.h" #include "jemalloc/internal/ph.h"
#ifndef __PGI
#define RB_COMPACT #define RB_COMPACT
#endif
#include "jemalloc/internal/rb.h" #include "jemalloc/internal/rb.h"
#include "jemalloc/internal/qr.h" #include "jemalloc/internal/qr.h"
#include "jemalloc/internal/ql.h" #include "jemalloc/internal/ql.h"
@@ -185,6 +193,9 @@ static const bool config_cache_oblivious =
#include "jemalloc/internal/jemalloc_internal_macros.h" #include "jemalloc/internal/jemalloc_internal_macros.h"
/* Page size index type. */
typedef unsigned pszind_t;
/* Size class index type. */ /* Size class index type. */
typedef unsigned szind_t; typedef unsigned szind_t;
@@ -234,7 +245,7 @@ typedef unsigned szind_t;
# ifdef __alpha__ # ifdef __alpha__
# define LG_QUANTUM 4 # define LG_QUANTUM 4
# endif # endif
# if (defined(__sparc64__) || defined(__sparcv9)) # if (defined(__sparc64__) || defined(__sparcv9) || defined(__sparc_v9__))
# define LG_QUANTUM 4 # define LG_QUANTUM 4
# endif # endif
# if (defined(__amd64__) || defined(__x86_64__) || defined(_M_X64)) # if (defined(__amd64__) || defined(__x86_64__) || defined(_M_X64))
@@ -332,7 +343,7 @@ typedef unsigned szind_t;
/* Return the nearest aligned address at or below a. */ /* Return the nearest aligned address at or below a. */
#define ALIGNMENT_ADDR2BASE(a, alignment) \ #define ALIGNMENT_ADDR2BASE(a, alignment) \
((void *)((uintptr_t)(a) & (-(alignment)))) ((void *)((uintptr_t)(a) & ((~(alignment)) + 1)))
/* Return the offset between a and the nearest aligned address at or below a. */ /* Return the offset between a and the nearest aligned address at or below a. */
#define ALIGNMENT_ADDR2OFFSET(a, alignment) \ #define ALIGNMENT_ADDR2OFFSET(a, alignment) \
@@ -340,7 +351,7 @@ typedef unsigned szind_t;
/* Return the smallest alignment multiple that is >= s. */ /* Return the smallest alignment multiple that is >= s. */
#define ALIGNMENT_CEILING(s, alignment) \ #define ALIGNMENT_CEILING(s, alignment) \
(((s) + (alignment - 1)) & (-(alignment))) (((s) + (alignment - 1)) & ((~(alignment)) + 1))
/* Declare a variable-length array. */ /* Declare a variable-length array. */
#if __STDC_VERSION__ < 199901L #if __STDC_VERSION__ < 199901L
@@ -364,6 +375,7 @@ typedef unsigned szind_t;
#include "jemalloc/internal/valgrind.h" #include "jemalloc/internal/valgrind.h"
#include "jemalloc/internal/util.h" #include "jemalloc/internal/util.h"
#include "jemalloc/internal/atomic.h" #include "jemalloc/internal/atomic.h"
#include "jemalloc/internal/spin.h"
#include "jemalloc/internal/prng.h" #include "jemalloc/internal/prng.h"
#include "jemalloc/internal/ticker.h" #include "jemalloc/internal/ticker.h"
#include "jemalloc/internal/ckh.h" #include "jemalloc/internal/ckh.h"
@@ -396,6 +408,7 @@ typedef unsigned szind_t;
#include "jemalloc/internal/valgrind.h" #include "jemalloc/internal/valgrind.h"
#include "jemalloc/internal/util.h" #include "jemalloc/internal/util.h"
#include "jemalloc/internal/atomic.h" #include "jemalloc/internal/atomic.h"
#include "jemalloc/internal/spin.h"
#include "jemalloc/internal/prng.h" #include "jemalloc/internal/prng.h"
#include "jemalloc/internal/ticker.h" #include "jemalloc/internal/ticker.h"
#include "jemalloc/internal/ckh.h" #include "jemalloc/internal/ckh.h"
@@ -455,11 +468,16 @@ extern unsigned narenas_auto;
*/ */
extern arena_t **arenas; extern arena_t **arenas;
/*
* pind2sz_tab encodes the same information as could be computed by
* pind2sz_compute().
*/
extern size_t const pind2sz_tab[NPSIZES];
/* /*
* index2size_tab encodes the same information as could be computed (at * index2size_tab encodes the same information as could be computed (at
* unacceptable cost in some code paths) by index2size_compute(). * unacceptable cost in some code paths) by index2size_compute().
*/ */
extern size_t const index2size_tab[NSIZES+1]; extern size_t const index2size_tab[NSIZES];
/* /*
* size2index_tab is a compact lookup table that rounds request sizes up to * size2index_tab is a compact lookup table that rounds request sizes up to
* size classes. In order to reduce cache footprint, the table is compressed, * size classes. In order to reduce cache footprint, the table is compressed,
@@ -467,6 +485,7 @@ extern size_t const index2size_tab[NSIZES+1];
*/ */
extern uint8_t const size2index_tab[]; extern uint8_t const size2index_tab[];
arena_t *a0get(void);
void *a0malloc(size_t size); void *a0malloc(size_t size);
void a0dalloc(void *ptr); void a0dalloc(void *ptr);
void *bootstrap_malloc(size_t size); void *bootstrap_malloc(size_t size);
@@ -492,6 +511,7 @@ void jemalloc_postfork_child(void);
#include "jemalloc/internal/valgrind.h" #include "jemalloc/internal/valgrind.h"
#include "jemalloc/internal/util.h" #include "jemalloc/internal/util.h"
#include "jemalloc/internal/atomic.h" #include "jemalloc/internal/atomic.h"
#include "jemalloc/internal/spin.h"
#include "jemalloc/internal/prng.h" #include "jemalloc/internal/prng.h"
#include "jemalloc/internal/ticker.h" #include "jemalloc/internal/ticker.h"
#include "jemalloc/internal/ckh.h" #include "jemalloc/internal/ckh.h"
@@ -524,6 +544,7 @@ void jemalloc_postfork_child(void);
#include "jemalloc/internal/valgrind.h" #include "jemalloc/internal/valgrind.h"
#include "jemalloc/internal/util.h" #include "jemalloc/internal/util.h"
#include "jemalloc/internal/atomic.h" #include "jemalloc/internal/atomic.h"
#include "jemalloc/internal/spin.h"
#include "jemalloc/internal/prng.h" #include "jemalloc/internal/prng.h"
#include "jemalloc/internal/ticker.h" #include "jemalloc/internal/ticker.h"
#include "jemalloc/internal/ckh.h" #include "jemalloc/internal/ckh.h"
@@ -543,6 +564,11 @@ void jemalloc_postfork_child(void);
#include "jemalloc/internal/huge.h" #include "jemalloc/internal/huge.h"
#ifndef JEMALLOC_ENABLE_INLINE #ifndef JEMALLOC_ENABLE_INLINE
pszind_t psz2ind(size_t psz);
size_t pind2sz_compute(pszind_t pind);
size_t pind2sz_lookup(pszind_t pind);
size_t pind2sz(pszind_t pind);
size_t psz2u(size_t psz);
szind_t size2index_compute(size_t size); szind_t size2index_compute(size_t size);
szind_t size2index_lookup(size_t size); szind_t size2index_lookup(size_t size);
szind_t size2index(size_t size); szind_t size2index(size_t size);
@@ -555,7 +581,7 @@ size_t s2u(size_t size);
size_t sa2u(size_t size, size_t alignment); size_t sa2u(size_t size, size_t alignment);
arena_t *arena_choose_impl(tsd_t *tsd, arena_t *arena, bool internal); arena_t *arena_choose_impl(tsd_t *tsd, arena_t *arena, bool internal);
arena_t *arena_choose(tsd_t *tsd, arena_t *arena); arena_t *arena_choose(tsd_t *tsd, arena_t *arena);
arena_t *arena_ichoose(tsdn_t *tsdn, arena_t *arena); arena_t *arena_ichoose(tsd_t *tsd, arena_t *arena);
arena_tdata_t *arena_tdata_get(tsd_t *tsd, unsigned ind, arena_tdata_t *arena_tdata_get(tsd_t *tsd, unsigned ind,
bool refresh_if_missing); bool refresh_if_missing);
arena_t *arena_get(tsdn_t *tsdn, unsigned ind, bool init_if_missing); arena_t *arena_get(tsdn_t *tsdn, unsigned ind, bool init_if_missing);
@@ -563,10 +589,90 @@ ticker_t *decay_ticker_get(tsd_t *tsd, unsigned ind);
#endif #endif
#if (defined(JEMALLOC_ENABLE_INLINE) || defined(JEMALLOC_C_)) #if (defined(JEMALLOC_ENABLE_INLINE) || defined(JEMALLOC_C_))
JEMALLOC_INLINE pszind_t
psz2ind(size_t psz)
{
if (unlikely(psz > HUGE_MAXCLASS))
return (NPSIZES);
{
pszind_t x = lg_floor((psz<<1)-1);
pszind_t shift = (x < LG_SIZE_CLASS_GROUP + LG_PAGE) ? 0 : x -
(LG_SIZE_CLASS_GROUP + LG_PAGE);
pszind_t grp = shift << LG_SIZE_CLASS_GROUP;
pszind_t lg_delta = (x < LG_SIZE_CLASS_GROUP + LG_PAGE + 1) ?
LG_PAGE : x - LG_SIZE_CLASS_GROUP - 1;
size_t delta_inverse_mask = ZI(-1) << lg_delta;
pszind_t mod = ((((psz-1) & delta_inverse_mask) >> lg_delta)) &
((ZU(1) << LG_SIZE_CLASS_GROUP) - 1);
pszind_t ind = grp + mod;
return (ind);
}
}
JEMALLOC_INLINE size_t
pind2sz_compute(pszind_t pind)
{
{
size_t grp = pind >> LG_SIZE_CLASS_GROUP;
size_t mod = pind & ((ZU(1) << LG_SIZE_CLASS_GROUP) - 1);
size_t grp_size_mask = ~((!!grp)-1);
size_t grp_size = ((ZU(1) << (LG_PAGE +
(LG_SIZE_CLASS_GROUP-1))) << grp) & grp_size_mask;
size_t shift = (grp == 0) ? 1 : grp;
size_t lg_delta = shift + (LG_PAGE-1);
size_t mod_size = (mod+1) << lg_delta;
size_t sz = grp_size + mod_size;
return (sz);
}
}
JEMALLOC_INLINE size_t
pind2sz_lookup(pszind_t pind)
{
size_t ret = (size_t)pind2sz_tab[pind];
assert(ret == pind2sz_compute(pind));
return (ret);
}
JEMALLOC_INLINE size_t
pind2sz(pszind_t pind)
{
assert(pind < NPSIZES);
return (pind2sz_lookup(pind));
}
JEMALLOC_INLINE size_t
psz2u(size_t psz)
{
if (unlikely(psz > HUGE_MAXCLASS))
return (0);
{
size_t x = lg_floor((psz<<1)-1);
size_t lg_delta = (x < LG_SIZE_CLASS_GROUP + LG_PAGE + 1) ?
LG_PAGE : x - LG_SIZE_CLASS_GROUP - 1;
size_t delta = ZU(1) << lg_delta;
size_t delta_mask = delta - 1;
size_t usize = (psz + delta_mask) & ~delta_mask;
return (usize);
}
}
JEMALLOC_INLINE szind_t JEMALLOC_INLINE szind_t
size2index_compute(size_t size) size2index_compute(size_t size)
{ {
if (unlikely(size > HUGE_MAXCLASS))
return (NSIZES);
#if (NTBINS != 0) #if (NTBINS != 0)
if (size <= (ZU(1) << LG_TINY_MAXCLASS)) { if (size <= (ZU(1) << LG_TINY_MAXCLASS)) {
szind_t lg_tmin = LG_TINY_MAXCLASS - NTBINS + 1; szind_t lg_tmin = LG_TINY_MAXCLASS - NTBINS + 1;
@@ -575,9 +681,7 @@ size2index_compute(size_t size)
} }
#endif #endif
{ {
szind_t x = unlikely(ZI(size) < 0) ? ((size<<1) ? szind_t x = lg_floor((size<<1)-1);
(ZU(1)<<(LG_SIZEOF_PTR+3)) : ((ZU(1)<<(LG_SIZEOF_PTR+3))-1))
: lg_floor((size<<1)-1);
szind_t shift = (x < LG_SIZE_CLASS_GROUP + LG_QUANTUM) ? 0 : szind_t shift = (x < LG_SIZE_CLASS_GROUP + LG_QUANTUM) ? 0 :
x - (LG_SIZE_CLASS_GROUP + LG_QUANTUM); x - (LG_SIZE_CLASS_GROUP + LG_QUANTUM);
szind_t grp = shift << LG_SIZE_CLASS_GROUP; szind_t grp = shift << LG_SIZE_CLASS_GROUP;
@@ -663,6 +767,8 @@ JEMALLOC_ALWAYS_INLINE size_t
s2u_compute(size_t size) s2u_compute(size_t size)
{ {
if (unlikely(size > HUGE_MAXCLASS))
return (0);
#if (NTBINS > 0) #if (NTBINS > 0)
if (size <= (ZU(1) << LG_TINY_MAXCLASS)) { if (size <= (ZU(1) << LG_TINY_MAXCLASS)) {
size_t lg_tmin = LG_TINY_MAXCLASS - NTBINS + 1; size_t lg_tmin = LG_TINY_MAXCLASS - NTBINS + 1;
@@ -672,9 +778,7 @@ s2u_compute(size_t size)
} }
#endif #endif
{ {
size_t x = unlikely(ZI(size) < 0) ? ((size<<1) ? size_t x = lg_floor((size<<1)-1);
(ZU(1)<<(LG_SIZEOF_PTR+3)) : ((ZU(1)<<(LG_SIZEOF_PTR+3))-1))
: lg_floor((size<<1)-1);
size_t lg_delta = (x < LG_SIZE_CLASS_GROUP + LG_QUANTUM + 1) size_t lg_delta = (x < LG_SIZE_CLASS_GROUP + LG_QUANTUM + 1)
? LG_QUANTUM : x - LG_SIZE_CLASS_GROUP - 1; ? LG_QUANTUM : x - LG_SIZE_CLASS_GROUP - 1;
size_t delta = ZU(1) << lg_delta; size_t delta = ZU(1) << lg_delta;
@@ -754,7 +858,7 @@ sa2u(size_t size, size_t alignment)
* Calculate the size of the over-size run that arena_palloc() * Calculate the size of the over-size run that arena_palloc()
* would need to allocate in order to guarantee the alignment. * would need to allocate in order to guarantee the alignment.
*/ */
if (usize + large_pad + alignment <= arena_maxrun) if (usize + large_pad + alignment - PAGE <= arena_maxrun)
return (usize); return (usize);
} }
@@ -784,7 +888,7 @@ sa2u(size_t size, size_t alignment)
* Calculate the multi-chunk mapping that huge_palloc() would need in * Calculate the multi-chunk mapping that huge_palloc() would need in
* order to guarantee the alignment. * order to guarantee the alignment.
*/ */
if (usize + alignment < usize) { if (usize + alignment - PAGE < usize) {
/* size_t overflow. */ /* size_t overflow. */
return (0); return (0);
} }
@@ -815,14 +919,10 @@ arena_choose(tsd_t *tsd, arena_t *arena)
} }
JEMALLOC_INLINE arena_t * JEMALLOC_INLINE arena_t *
arena_ichoose(tsdn_t *tsdn, arena_t *arena) arena_ichoose(tsd_t *tsd, arena_t *arena)
{ {
assert(!tsdn_null(tsdn) || arena != NULL); return (arena_choose_impl(tsd, arena, true));
if (!tsdn_null(tsdn))
return (arena_choose_impl(tsdn_tsd(tsdn), NULL, true));
return (arena);
} }
JEMALLOC_INLINE arena_tdata_t * JEMALLOC_INLINE arena_tdata_t *

View File

@@ -14,11 +14,26 @@
# if !defined(SYS_write) && defined(__NR_write) # if !defined(SYS_write) && defined(__NR_write)
# define SYS_write __NR_write # define SYS_write __NR_write
# endif # endif
# if defined(SYS_open) && defined(__aarch64__)
/* Android headers may define SYS_open to __NR_open even though
* __NR_open may not exist on AArch64 (superseded by __NR_openat). */
# undef SYS_open
# endif
# include <sys/uio.h> # include <sys/uio.h>
# endif # endif
# include <pthread.h> # include <pthread.h>
# ifdef JEMALLOC_OS_UNFAIR_LOCK
# include <os/lock.h>
# endif
# ifdef JEMALLOC_GLIBC_MALLOC_HOOK
# include <sched.h>
# endif
# include <errno.h> # include <errno.h>
# include <sys/time.h> # include <sys/time.h>
# include <time.h>
# ifdef JEMALLOC_HAVE_MACH_ABSOLUTE_TIME
# include <mach/mach_time.h>
# endif
#endif #endif
#include <sys/types.h> #include <sys/types.h>

View File

@@ -56,9 +56,9 @@
#undef JEMALLOC_HAVE_BUILTIN_CLZ #undef JEMALLOC_HAVE_BUILTIN_CLZ
/* /*
* Defined if madvise(2) is available. * Defined if os_unfair_lock_*() functions are available, as provided by Darwin.
*/ */
#undef JEMALLOC_HAVE_MADVISE #undef JEMALLOC_OS_UNFAIR_LOCK
/* /*
* Defined if OSSpin*() functions are available, as provided by Darwin, and * Defined if OSSpin*() functions are available, as provided by Darwin, and
@@ -66,6 +66,9 @@
*/ */
#undef JEMALLOC_OSSPIN #undef JEMALLOC_OSSPIN
/* Defined if syscall(2) is usable. */
#undef JEMALLOC_USE_SYSCALL
/* /*
* Defined if secure_getenv(3) is available. * Defined if secure_getenv(3) is available.
*/ */
@@ -76,6 +79,24 @@
*/ */
#undef JEMALLOC_HAVE_ISSETUGID #undef JEMALLOC_HAVE_ISSETUGID
/* Defined if pthread_atfork(3) is available. */
#undef JEMALLOC_HAVE_PTHREAD_ATFORK
/*
* Defined if clock_gettime(CLOCK_MONOTONIC_COARSE, ...) is available.
*/
#undef JEMALLOC_HAVE_CLOCK_MONOTONIC_COARSE
/*
* Defined if clock_gettime(CLOCK_MONOTONIC, ...) is available.
*/
#undef JEMALLOC_HAVE_CLOCK_MONOTONIC
/*
* Defined if mach_absolute_time() is available.
*/
#undef JEMALLOC_HAVE_MACH_ABSOLUTE_TIME
/* /*
* Defined if _malloc_thread_cleanup() exists. At least in the case of * Defined if _malloc_thread_cleanup() exists. At least in the case of
* FreeBSD, pthread_key_create() allocates, which if used during malloc * FreeBSD, pthread_key_create() allocates, which if used during malloc
@@ -188,6 +209,12 @@
/* TLS is used to map arenas and magazine caches to threads. */ /* TLS is used to map arenas and magazine caches to threads. */
#undef JEMALLOC_TLS #undef JEMALLOC_TLS
/*
* Used to mark unreachable code to quiet "end of non-void" compiler warnings.
* Don't use this directly; instead use unreachable() from util.h
*/
#undef JEMALLOC_INTERNAL_UNREACHABLE
/* /*
* ffs*() functions to use for bitmapping. Don't use these directly; instead, * ffs*() functions to use for bitmapping. Don't use these directly; instead,
* use ffs_*() from util.h. * use ffs_*() from util.h.
@@ -212,7 +239,6 @@
* Darwin (OS X) uses zones to work around Mach-O symbol override shortcomings. * Darwin (OS X) uses zones to work around Mach-O symbol override shortcomings.
*/ */
#undef JEMALLOC_ZONE #undef JEMALLOC_ZONE
#undef JEMALLOC_ZONE_VERSION
/* /*
* Methods for determining whether the OS overcommits. * Methods for determining whether the OS overcommits.
@@ -223,18 +249,29 @@
#undef JEMALLOC_SYSCTL_VM_OVERCOMMIT #undef JEMALLOC_SYSCTL_VM_OVERCOMMIT
#undef JEMALLOC_PROC_SYS_VM_OVERCOMMIT_MEMORY #undef JEMALLOC_PROC_SYS_VM_OVERCOMMIT_MEMORY
/* Defined if madvise(2) is available. */
#undef JEMALLOC_HAVE_MADVISE
/*
* Defined if transparent huge pages are supported via the MADV_[NO]HUGEPAGE
* arguments to madvise(2).
*/
#undef JEMALLOC_HAVE_MADVISE_HUGE
/* /*
* Methods for purging unused pages differ between operating systems. * Methods for purging unused pages differ between operating systems.
* *
* madvise(..., MADV_DONTNEED) : On Linux, this immediately discards pages, * madvise(..., MADV_FREE) : This marks pages as being unused, such that they
* such that new pages will be demand-zeroed if * will be discarded rather than swapped out.
* the address region is later touched. * madvise(..., MADV_DONTNEED) : This immediately discards pages, such that
* madvise(..., MADV_FREE) : On FreeBSD and Darwin, this marks pages as being * new pages will be demand-zeroed if the
* unused, such that they will be discarded rather * address region is later touched.
* than swapped out.
*/ */
#undef JEMALLOC_PURGE_MADVISE_DONTNEED
#undef JEMALLOC_PURGE_MADVISE_FREE #undef JEMALLOC_PURGE_MADVISE_FREE
#undef JEMALLOC_PURGE_MADVISE_DONTNEED
/* Defined if transparent huge page support is enabled. */
#undef JEMALLOC_THP
/* Define if operating system has alloca.h header. */ /* Define if operating system has alloca.h header. */
#undef JEMALLOC_HAS_ALLOCA_H #undef JEMALLOC_HAS_ALLOCA_H

View File

@@ -76,7 +76,7 @@ mb_write(void)
: "memory" /* Clobbers. */ : "memory" /* Clobbers. */
); );
} }
#elif defined(__sparc64__) #elif defined(__sparc__) && defined(__arch64__)
JEMALLOC_INLINE void JEMALLOC_INLINE void
mb_write(void) mb_write(void)
{ {
@@ -105,8 +105,8 @@ mb_write(void)
malloc_mutex_t mtx; malloc_mutex_t mtx;
malloc_mutex_init(&mtx, "mb", WITNESS_RANK_OMIT); malloc_mutex_init(&mtx, "mb", WITNESS_RANK_OMIT);
malloc_mutex_lock(NULL, &mtx); malloc_mutex_lock(TSDN_NULL, &mtx);
malloc_mutex_unlock(NULL, &mtx); malloc_mutex_unlock(TSDN_NULL, &mtx);
} }
#endif #endif
#endif #endif

View File

@@ -5,6 +5,9 @@ typedef struct malloc_mutex_s malloc_mutex_t;
#ifdef _WIN32 #ifdef _WIN32
# define MALLOC_MUTEX_INITIALIZER # define MALLOC_MUTEX_INITIALIZER
#elif (defined(JEMALLOC_OS_UNFAIR_LOCK))
# define MALLOC_MUTEX_INITIALIZER \
{OS_UNFAIR_LOCK_INIT, WITNESS_INITIALIZER(WITNESS_RANK_OMIT)}
#elif (defined(JEMALLOC_OSSPIN)) #elif (defined(JEMALLOC_OSSPIN))
# define MALLOC_MUTEX_INITIALIZER {0, WITNESS_INITIALIZER(WITNESS_RANK_OMIT)} # define MALLOC_MUTEX_INITIALIZER {0, WITNESS_INITIALIZER(WITNESS_RANK_OMIT)}
#elif (defined(JEMALLOC_MUTEX_INIT_CB)) #elif (defined(JEMALLOC_MUTEX_INIT_CB))
@@ -35,6 +38,8 @@ struct malloc_mutex_s {
# else # else
CRITICAL_SECTION lock; CRITICAL_SECTION lock;
# endif # endif
#elif (defined(JEMALLOC_OS_UNFAIR_LOCK))
os_unfair_lock lock;
#elif (defined(JEMALLOC_OSSPIN)) #elif (defined(JEMALLOC_OSSPIN))
OSSpinLock lock; OSSpinLock lock;
#elif (defined(JEMALLOC_MUTEX_INIT_CB)) #elif (defined(JEMALLOC_MUTEX_INIT_CB))
@@ -80,35 +85,39 @@ JEMALLOC_INLINE void
malloc_mutex_lock(tsdn_t *tsdn, malloc_mutex_t *mutex) malloc_mutex_lock(tsdn_t *tsdn, malloc_mutex_t *mutex)
{ {
witness_assert_not_owner(tsdn, &mutex->witness);
if (isthreaded) { if (isthreaded) {
witness_assert_not_owner(tsdn, &mutex->witness);
#ifdef _WIN32 #ifdef _WIN32
# if _WIN32_WINNT >= 0x0600 # if _WIN32_WINNT >= 0x0600
AcquireSRWLockExclusive(&mutex->lock); AcquireSRWLockExclusive(&mutex->lock);
# else # else
EnterCriticalSection(&mutex->lock); EnterCriticalSection(&mutex->lock);
# endif # endif
#elif (defined(JEMALLOC_OS_UNFAIR_LOCK))
os_unfair_lock_lock(&mutex->lock);
#elif (defined(JEMALLOC_OSSPIN)) #elif (defined(JEMALLOC_OSSPIN))
OSSpinLockLock(&mutex->lock); OSSpinLockLock(&mutex->lock);
#else #else
pthread_mutex_lock(&mutex->lock); pthread_mutex_lock(&mutex->lock);
#endif #endif
witness_lock(tsdn, &mutex->witness);
} }
witness_lock(tsdn, &mutex->witness);
} }
JEMALLOC_INLINE void JEMALLOC_INLINE void
malloc_mutex_unlock(tsdn_t *tsdn, malloc_mutex_t *mutex) malloc_mutex_unlock(tsdn_t *tsdn, malloc_mutex_t *mutex)
{ {
witness_unlock(tsdn, &mutex->witness);
if (isthreaded) { if (isthreaded) {
witness_unlock(tsdn, &mutex->witness);
#ifdef _WIN32 #ifdef _WIN32
# if _WIN32_WINNT >= 0x0600 # if _WIN32_WINNT >= 0x0600
ReleaseSRWLockExclusive(&mutex->lock); ReleaseSRWLockExclusive(&mutex->lock);
# else # else
LeaveCriticalSection(&mutex->lock); LeaveCriticalSection(&mutex->lock);
# endif # endif
#elif (defined(JEMALLOC_OS_UNFAIR_LOCK))
os_unfair_lock_unlock(&mutex->lock);
#elif (defined(JEMALLOC_OSSPIN)) #elif (defined(JEMALLOC_OSSPIN))
OSSpinLockUnlock(&mutex->lock); OSSpinLockUnlock(&mutex->lock);
#else #else
@@ -121,16 +130,14 @@ JEMALLOC_INLINE void
malloc_mutex_assert_owner(tsdn_t *tsdn, malloc_mutex_t *mutex) malloc_mutex_assert_owner(tsdn_t *tsdn, malloc_mutex_t *mutex)
{ {
if (isthreaded) witness_assert_owner(tsdn, &mutex->witness);
witness_assert_owner(tsdn, &mutex->witness);
} }
JEMALLOC_INLINE void JEMALLOC_INLINE void
malloc_mutex_assert_not_owner(tsdn_t *tsdn, malloc_mutex_t *mutex) malloc_mutex_assert_not_owner(tsdn_t *tsdn, malloc_mutex_t *mutex)
{ {
if (isthreaded) witness_assert_not_owner(tsdn, &mutex->witness);
witness_assert_not_owner(tsdn, &mutex->witness);
} }
#endif #endif

View File

@@ -1,9 +1,6 @@
/******************************************************************************/ /******************************************************************************/
#ifdef JEMALLOC_H_TYPES #ifdef JEMALLOC_H_TYPES
#define JEMALLOC_CLOCK_GETTIME defined(_POSIX_MONOTONIC_CLOCK) \
&& _POSIX_MONOTONIC_CLOCK >= 0
typedef struct nstime_s nstime_t; typedef struct nstime_s nstime_t;
/* Maximum supported number of seconds (~584 years). */ /* Maximum supported number of seconds (~584 years). */
@@ -34,9 +31,12 @@ void nstime_imultiply(nstime_t *time, uint64_t multiplier);
void nstime_idivide(nstime_t *time, uint64_t divisor); void nstime_idivide(nstime_t *time, uint64_t divisor);
uint64_t nstime_divide(const nstime_t *time, const nstime_t *divisor); uint64_t nstime_divide(const nstime_t *time, const nstime_t *divisor);
#ifdef JEMALLOC_JET #ifdef JEMALLOC_JET
typedef bool (nstime_monotonic_t)(void);
extern nstime_monotonic_t *nstime_monotonic;
typedef bool (nstime_update_t)(nstime_t *); typedef bool (nstime_update_t)(nstime_t *);
extern nstime_update_t *nstime_update; extern nstime_update_t *nstime_update;
#else #else
bool nstime_monotonic(void);
bool nstime_update(nstime_t *time); bool nstime_update(nstime_t *time);
#endif #endif

View File

@@ -16,6 +16,8 @@ void *pages_trim(void *addr, size_t alloc_size, size_t leadsize,
bool pages_commit(void *addr, size_t size); bool pages_commit(void *addr, size_t size);
bool pages_decommit(void *addr, size_t size); bool pages_decommit(void *addr, size_t size);
bool pages_purge(void *addr, size_t size); bool pages_purge(void *addr, size_t size);
bool pages_huge(void *addr, size_t size);
bool pages_nohuge(void *addr, size_t size);
void pages_boot(void); void pages_boot(void);
#endif /* JEMALLOC_H_EXTERNS */ #endif /* JEMALLOC_H_EXTERNS */

View File

@@ -1,4 +1,5 @@
a0dalloc a0dalloc
a0get
a0malloc a0malloc
arena_aalloc arena_aalloc
arena_alloc_junk_small arena_alloc_junk_small
@@ -35,6 +36,7 @@ arena_decay_time_get
arena_decay_time_set arena_decay_time_set
arena_dss_prec_get arena_dss_prec_get
arena_dss_prec_set arena_dss_prec_set
arena_extent_sn_next
arena_get arena_get
arena_ichoose arena_ichoose
arena_init arena_init
@@ -167,20 +169,15 @@ chunk_dalloc_mmap
chunk_dalloc_wrapper chunk_dalloc_wrapper
chunk_deregister chunk_deregister
chunk_dss_boot chunk_dss_boot
chunk_dss_postfork_child chunk_dss_mergeable
chunk_dss_postfork_parent
chunk_dss_prec_get chunk_dss_prec_get
chunk_dss_prec_set chunk_dss_prec_set
chunk_dss_prefork
chunk_hooks_default chunk_hooks_default
chunk_hooks_get chunk_hooks_get
chunk_hooks_set chunk_hooks_set
chunk_in_dss chunk_in_dss
chunk_lookup chunk_lookup
chunk_npages chunk_npages
chunk_postfork_child
chunk_postfork_parent
chunk_prefork
chunk_purge_wrapper chunk_purge_wrapper
chunk_register chunk_register
chunks_rtree chunks_rtree
@@ -222,8 +219,12 @@ extent_node_prof_tctx_get
extent_node_prof_tctx_set extent_node_prof_tctx_set
extent_node_size_get extent_node_size_get
extent_node_size_set extent_node_size_set
extent_node_sn_get
extent_node_sn_set
extent_node_zeroed_get extent_node_zeroed_get
extent_node_zeroed_set extent_node_zeroed_set
extent_size_quantize_ceil
extent_size_quantize_floor
extent_tree_ad_destroy extent_tree_ad_destroy
extent_tree_ad_destroy_recurse extent_tree_ad_destroy_recurse
extent_tree_ad_empty extent_tree_ad_empty
@@ -243,25 +244,25 @@ extent_tree_ad_reverse_iter
extent_tree_ad_reverse_iter_recurse extent_tree_ad_reverse_iter_recurse
extent_tree_ad_reverse_iter_start extent_tree_ad_reverse_iter_start
extent_tree_ad_search extent_tree_ad_search
extent_tree_szad_destroy extent_tree_szsnad_destroy
extent_tree_szad_destroy_recurse extent_tree_szsnad_destroy_recurse
extent_tree_szad_empty extent_tree_szsnad_empty
extent_tree_szad_first extent_tree_szsnad_first
extent_tree_szad_insert extent_tree_szsnad_insert
extent_tree_szad_iter extent_tree_szsnad_iter
extent_tree_szad_iter_recurse extent_tree_szsnad_iter_recurse
extent_tree_szad_iter_start extent_tree_szsnad_iter_start
extent_tree_szad_last extent_tree_szsnad_last
extent_tree_szad_new extent_tree_szsnad_new
extent_tree_szad_next extent_tree_szsnad_next
extent_tree_szad_nsearch extent_tree_szsnad_nsearch
extent_tree_szad_prev extent_tree_szsnad_prev
extent_tree_szad_psearch extent_tree_szsnad_psearch
extent_tree_szad_remove extent_tree_szsnad_remove
extent_tree_szad_reverse_iter extent_tree_szsnad_reverse_iter
extent_tree_szad_reverse_iter_recurse extent_tree_szsnad_reverse_iter_recurse
extent_tree_szad_reverse_iter_start extent_tree_szsnad_reverse_iter_start
extent_tree_szad_search extent_tree_szsnad_search
ffs_llu ffs_llu
ffs_lu ffs_lu
ffs_u ffs_u
@@ -360,6 +361,7 @@ nstime_idivide
nstime_imultiply nstime_imultiply
nstime_init nstime_init
nstime_init2 nstime_init2
nstime_monotonic
nstime_ns nstime_ns
nstime_nsec nstime_nsec
nstime_sec nstime_sec
@@ -390,6 +392,7 @@ opt_quarantine
opt_redzone opt_redzone
opt_stats_print opt_stats_print
opt_tcache opt_tcache
opt_thp
opt_utrace opt_utrace
opt_xmalloc opt_xmalloc
opt_zero opt_zero
@@ -397,15 +400,28 @@ p2rz
pages_boot pages_boot
pages_commit pages_commit
pages_decommit pages_decommit
pages_huge
pages_map pages_map
pages_nohuge
pages_purge pages_purge
pages_trim pages_trim
pages_unmap pages_unmap
pind2sz
pind2sz_compute
pind2sz_lookup
pind2sz_tab
pow2_ceil_u32 pow2_ceil_u32
pow2_ceil_u64 pow2_ceil_u64
pow2_ceil_zu pow2_ceil_zu
prng_lg_range prng_lg_range_u32
prng_range prng_lg_range_u64
prng_lg_range_zu
prng_range_u32
prng_range_u64
prng_range_zu
prng_state_next_u32
prng_state_next_u64
prng_state_next_zu
prof_active prof_active
prof_active_get prof_active_get
prof_active_get_unlocked prof_active_get_unlocked
@@ -454,12 +470,13 @@ prof_thread_active_init_set
prof_thread_active_set prof_thread_active_set
prof_thread_name_get prof_thread_name_get
prof_thread_name_set prof_thread_name_set
psz2ind
psz2u
purge_mode_names purge_mode_names
quarantine quarantine
quarantine_alloc_hook quarantine_alloc_hook
quarantine_alloc_hook_work quarantine_alloc_hook_work
quarantine_cleanup quarantine_cleanup
register_zone
rtree_child_read rtree_child_read
rtree_child_read_hard rtree_child_read_hard
rtree_child_tryread rtree_child_tryread
@@ -477,7 +494,6 @@ rtree_val_read
rtree_val_write rtree_val_write
run_quantize_ceil run_quantize_ceil
run_quantize_floor run_quantize_floor
run_quantize_max
s2u s2u
s2u_compute s2u_compute
s2u_lookup s2u_lookup
@@ -487,6 +503,8 @@ size2index
size2index_compute size2index_compute
size2index_lookup size2index_lookup
size2index_tab size2index_tab
spin_adaptive
spin_init
stats_cactive stats_cactive
stats_cactive_add stats_cactive_add
stats_cactive_get stats_cactive_get
@@ -514,6 +532,9 @@ tcache_flush
tcache_get tcache_get
tcache_get_hard tcache_get_hard
tcache_maxclass tcache_maxclass
tcache_postfork_child
tcache_postfork_parent
tcache_prefork
tcache_salloc tcache_salloc
tcache_stats_merge tcache_stats_merge
tcaches tcaches
@@ -545,7 +566,9 @@ tsd_booted_get
tsd_cleanup tsd_cleanup
tsd_cleanup_wrapper tsd_cleanup_wrapper
tsd_fetch tsd_fetch
tsd_fetch_impl
tsd_get tsd_get
tsd_get_allocates
tsd_iarena_get tsd_iarena_get
tsd_iarena_set tsd_iarena_set
tsd_iarenap_get tsd_iarenap_get
@@ -595,18 +618,22 @@ valgrind_freelike_block
valgrind_make_mem_defined valgrind_make_mem_defined
valgrind_make_mem_noaccess valgrind_make_mem_noaccess
valgrind_make_mem_undefined valgrind_make_mem_undefined
witness_assert_depth
witness_assert_depth_to_rank
witness_assert_lockless witness_assert_lockless
witness_assert_not_owner witness_assert_not_owner
witness_assert_owner witness_assert_owner
witness_depth_error
witness_fork_cleanup witness_fork_cleanup
witness_init witness_init
witness_lock witness_lock
witness_lock_error witness_lock_error
witness_lockless_error
witness_not_owner_error witness_not_owner_error
witness_owner
witness_owner_error witness_owner_error
witness_postfork_child witness_postfork_child
witness_postfork_parent witness_postfork_parent
witness_prefork witness_prefork
witness_unlock witness_unlock
witnesses_cleanup witnesses_cleanup
zone_register

View File

@@ -19,8 +19,12 @@
* the next has a cycle of 4, etc. For this reason, we prefer to use the upper * the next has a cycle of 4, etc. For this reason, we prefer to use the upper
* bits. * bits.
*/ */
#define PRNG_A UINT64_C(6364136223846793005)
#define PRNG_C UINT64_C(1442695040888963407) #define PRNG_A_32 UINT32_C(1103515241)
#define PRNG_C_32 UINT32_C(12347)
#define PRNG_A_64 UINT64_C(6364136223846793005)
#define PRNG_C_64 UINT64_C(1442695040888963407)
#endif /* JEMALLOC_H_TYPES */ #endif /* JEMALLOC_H_TYPES */
/******************************************************************************/ /******************************************************************************/
@@ -35,28 +39,133 @@
#ifdef JEMALLOC_H_INLINES #ifdef JEMALLOC_H_INLINES
#ifndef JEMALLOC_ENABLE_INLINE #ifndef JEMALLOC_ENABLE_INLINE
uint64_t prng_lg_range(uint64_t *state, unsigned lg_range); uint32_t prng_state_next_u32(uint32_t state);
uint64_t prng_range(uint64_t *state, uint64_t range); uint64_t prng_state_next_u64(uint64_t state);
size_t prng_state_next_zu(size_t state);
uint32_t prng_lg_range_u32(uint32_t *state, unsigned lg_range,
bool atomic);
uint64_t prng_lg_range_u64(uint64_t *state, unsigned lg_range);
size_t prng_lg_range_zu(size_t *state, unsigned lg_range, bool atomic);
uint32_t prng_range_u32(uint32_t *state, uint32_t range, bool atomic);
uint64_t prng_range_u64(uint64_t *state, uint64_t range);
size_t prng_range_zu(size_t *state, size_t range, bool atomic);
#endif #endif
#if (defined(JEMALLOC_ENABLE_INLINE) || defined(JEMALLOC_PRNG_C_)) #if (defined(JEMALLOC_ENABLE_INLINE) || defined(JEMALLOC_PRNG_C_))
JEMALLOC_ALWAYS_INLINE uint64_t JEMALLOC_ALWAYS_INLINE uint32_t
prng_lg_range(uint64_t *state, unsigned lg_range) prng_state_next_u32(uint32_t state)
{ {
uint64_t ret;
return ((state * PRNG_A_32) + PRNG_C_32);
}
JEMALLOC_ALWAYS_INLINE uint64_t
prng_state_next_u64(uint64_t state)
{
return ((state * PRNG_A_64) + PRNG_C_64);
}
JEMALLOC_ALWAYS_INLINE size_t
prng_state_next_zu(size_t state)
{
#if LG_SIZEOF_PTR == 2
return ((state * PRNG_A_32) + PRNG_C_32);
#elif LG_SIZEOF_PTR == 3
return ((state * PRNG_A_64) + PRNG_C_64);
#else
#error Unsupported pointer size
#endif
}
JEMALLOC_ALWAYS_INLINE uint32_t
prng_lg_range_u32(uint32_t *state, unsigned lg_range, bool atomic)
{
uint32_t ret, state1;
assert(lg_range > 0);
assert(lg_range <= 32);
if (atomic) {
uint32_t state0;
do {
state0 = atomic_read_uint32(state);
state1 = prng_state_next_u32(state0);
} while (atomic_cas_uint32(state, state0, state1));
} else {
state1 = prng_state_next_u32(*state);
*state = state1;
}
ret = state1 >> (32 - lg_range);
return (ret);
}
/* 64-bit atomic operations cannot be supported on all relevant platforms. */
JEMALLOC_ALWAYS_INLINE uint64_t
prng_lg_range_u64(uint64_t *state, unsigned lg_range)
{
uint64_t ret, state1;
assert(lg_range > 0); assert(lg_range > 0);
assert(lg_range <= 64); assert(lg_range <= 64);
ret = (*state * PRNG_A) + PRNG_C; state1 = prng_state_next_u64(*state);
*state = ret; *state = state1;
ret >>= (64 - lg_range); ret = state1 >> (64 - lg_range);
return (ret);
}
JEMALLOC_ALWAYS_INLINE size_t
prng_lg_range_zu(size_t *state, unsigned lg_range, bool atomic)
{
size_t ret, state1;
assert(lg_range > 0);
assert(lg_range <= ZU(1) << (3 + LG_SIZEOF_PTR));
if (atomic) {
size_t state0;
do {
state0 = atomic_read_z(state);
state1 = prng_state_next_zu(state0);
} while (atomic_cas_z(state, state0, state1));
} else {
state1 = prng_state_next_zu(*state);
*state = state1;
}
ret = state1 >> ((ZU(1) << (3 + LG_SIZEOF_PTR)) - lg_range);
return (ret);
}
JEMALLOC_ALWAYS_INLINE uint32_t
prng_range_u32(uint32_t *state, uint32_t range, bool atomic)
{
uint32_t ret;
unsigned lg_range;
assert(range > 1);
/* Compute the ceiling of lg(range). */
lg_range = ffs_u32(pow2_ceil_u32(range)) - 1;
/* Generate a result in [0..range) via repeated trial. */
do {
ret = prng_lg_range_u32(state, lg_range, atomic);
} while (ret >= range);
return (ret); return (ret);
} }
JEMALLOC_ALWAYS_INLINE uint64_t JEMALLOC_ALWAYS_INLINE uint64_t
prng_range(uint64_t *state, uint64_t range) prng_range_u64(uint64_t *state, uint64_t range)
{ {
uint64_t ret; uint64_t ret;
unsigned lg_range; unsigned lg_range;
@@ -68,7 +177,26 @@ prng_range(uint64_t *state, uint64_t range)
/* Generate a result in [0..range) via repeated trial. */ /* Generate a result in [0..range) via repeated trial. */
do { do {
ret = prng_lg_range(state, lg_range); ret = prng_lg_range_u64(state, lg_range);
} while (ret >= range);
return (ret);
}
JEMALLOC_ALWAYS_INLINE size_t
prng_range_zu(size_t *state, size_t range, bool atomic)
{
size_t ret;
unsigned lg_range;
assert(range > 1);
/* Compute the ceiling of lg(range). */
lg_range = ffs_u64(pow2_ceil_u64(range)) - 1;
/* Generate a result in [0..range) via repeated trial. */
do {
ret = prng_lg_range_zu(state, lg_range, atomic);
} while (ret >= range); } while (ret >= range);
return (ret); return (ret);

View File

@@ -299,9 +299,9 @@ extern prof_dump_header_t *prof_dump_header;
void prof_idump(tsdn_t *tsdn); void prof_idump(tsdn_t *tsdn);
bool prof_mdump(tsd_t *tsd, const char *filename); bool prof_mdump(tsd_t *tsd, const char *filename);
void prof_gdump(tsdn_t *tsdn); void prof_gdump(tsdn_t *tsdn);
prof_tdata_t *prof_tdata_init(tsdn_t *tsdn); prof_tdata_t *prof_tdata_init(tsd_t *tsd);
prof_tdata_t *prof_tdata_reinit(tsd_t *tsd, prof_tdata_t *tdata); prof_tdata_t *prof_tdata_reinit(tsd_t *tsd, prof_tdata_t *tdata);
void prof_reset(tsdn_t *tsdn, size_t lg_sample); void prof_reset(tsd_t *tsd, size_t lg_sample);
void prof_tdata_cleanup(tsd_t *tsd); void prof_tdata_cleanup(tsd_t *tsd);
bool prof_active_get(tsdn_t *tsdn); bool prof_active_get(tsdn_t *tsdn);
bool prof_active_set(tsdn_t *tsdn, bool active); bool prof_active_set(tsdn_t *tsdn, bool active);
@@ -315,7 +315,7 @@ bool prof_gdump_get(tsdn_t *tsdn);
bool prof_gdump_set(tsdn_t *tsdn, bool active); bool prof_gdump_set(tsdn_t *tsdn, bool active);
void prof_boot0(void); void prof_boot0(void);
void prof_boot1(void); void prof_boot1(void);
bool prof_boot2(tsdn_t *tsdn); bool prof_boot2(tsd_t *tsd);
void prof_prefork0(tsdn_t *tsdn); void prof_prefork0(tsdn_t *tsdn);
void prof_prefork1(tsdn_t *tsdn); void prof_prefork1(tsdn_t *tsdn);
void prof_postfork_parent(tsdn_t *tsdn); void prof_postfork_parent(tsdn_t *tsdn);
@@ -384,7 +384,7 @@ prof_tdata_get(tsd_t *tsd, bool create)
if (create) { if (create) {
if (unlikely(tdata == NULL)) { if (unlikely(tdata == NULL)) {
if (tsd_nominal(tsd)) { if (tsd_nominal(tsd)) {
tdata = prof_tdata_init(tsd_tsdn(tsd)); tdata = prof_tdata_init(tsd);
tsd_prof_tdata_set(tsd, tdata); tsd_prof_tdata_set(tsd, tdata);
} }
} else if (unlikely(tdata->expired)) { } else if (unlikely(tdata->expired)) {
@@ -513,6 +513,7 @@ prof_realloc(tsd_t *tsd, const void *ptr, size_t usize, prof_tctx_t *tctx,
* though its actual usize was insufficient to cross the * though its actual usize was insufficient to cross the
* sample threshold. * sample threshold.
*/ */
prof_alloc_rollback(tsd, tctx, true);
tctx = (prof_tctx_t *)(uintptr_t)1U; tctx = (prof_tctx_t *)(uintptr_t)1U;
} }
} }

View File

@@ -48,6 +48,21 @@ size_class() {
lg_p=$5 lg_p=$5
lg_kmax=$6 lg_kmax=$6
if [ ${lg_delta} -ge ${lg_p} ] ; then
psz="yes"
else
pow2 ${lg_p}; p=${pow2_result}
pow2 ${lg_grp}; grp=${pow2_result}
pow2 ${lg_delta}; delta=${pow2_result}
sz=$((${grp} + ${delta} * ${ndelta}))
npgs=$((${sz} / ${p}))
if [ ${sz} -eq $((${npgs} * ${p})) ] ; then
psz="yes"
else
psz="no"
fi
fi
lg ${ndelta}; lg_ndelta=${lg_result}; pow2 ${lg_ndelta} lg ${ndelta}; lg_ndelta=${lg_result}; pow2 ${lg_ndelta}
if [ ${pow2_result} -lt ${ndelta} ] ; then if [ ${pow2_result} -lt ${ndelta} ] ; then
rem="yes" rem="yes"
@@ -74,14 +89,15 @@ size_class() {
else else
lg_delta_lookup="no" lg_delta_lookup="no"
fi fi
printf ' SC(%3d, %6d, %8d, %6d, %3s, %2s) \\\n' ${index} ${lg_grp} ${lg_delta} ${ndelta} ${bin} ${lg_delta_lookup} printf ' SC(%3d, %6d, %8d, %6d, %3s, %3s, %2s) \\\n' ${index} ${lg_grp} ${lg_delta} ${ndelta} ${psz} ${bin} ${lg_delta_lookup}
# Defined upon return: # Defined upon return:
# - lg_delta_lookup (${lg_delta} or "no") # - psz ("yes" or "no")
# - bin ("yes" or "no") # - bin ("yes" or "no")
# - lg_delta_lookup (${lg_delta} or "no")
} }
sep_line() { sep_line() {
echo " \\" echo " \\"
} }
size_classes() { size_classes() {
@@ -95,12 +111,13 @@ size_classes() {
pow2 ${lg_g}; g=${pow2_result} pow2 ${lg_g}; g=${pow2_result}
echo "#define SIZE_CLASSES \\" echo "#define SIZE_CLASSES \\"
echo " /* index, lg_grp, lg_delta, ndelta, bin, lg_delta_lookup */ \\" echo " /* index, lg_grp, lg_delta, ndelta, psz, bin, lg_delta_lookup */ \\"
ntbins=0 ntbins=0
nlbins=0 nlbins=0
lg_tiny_maxclass='"NA"' lg_tiny_maxclass='"NA"'
nbins=0 nbins=0
npsizes=0
# Tiny size classes. # Tiny size classes.
ndelta=0 ndelta=0
@@ -112,6 +129,9 @@ size_classes() {
if [ ${lg_delta_lookup} != "no" ] ; then if [ ${lg_delta_lookup} != "no" ] ; then
nlbins=$((${index} + 1)) nlbins=$((${index} + 1))
fi fi
if [ ${psz} = "yes" ] ; then
npsizes=$((${npsizes} + 1))
fi
if [ ${bin} != "no" ] ; then if [ ${bin} != "no" ] ; then
nbins=$((${index} + 1)) nbins=$((${index} + 1))
fi fi
@@ -133,11 +153,17 @@ size_classes() {
index=$((${index} + 1)) index=$((${index} + 1))
lg_grp=$((${lg_grp} + 1)) lg_grp=$((${lg_grp} + 1))
lg_delta=$((${lg_delta} + 1)) lg_delta=$((${lg_delta} + 1))
if [ ${psz} = "yes" ] ; then
npsizes=$((${npsizes} + 1))
fi
fi fi
while [ ${ndelta} -lt ${g} ] ; do while [ ${ndelta} -lt ${g} ] ; do
size_class ${index} ${lg_grp} ${lg_delta} ${ndelta} ${lg_p} ${lg_kmax} size_class ${index} ${lg_grp} ${lg_delta} ${ndelta} ${lg_p} ${lg_kmax}
index=$((${index} + 1)) index=$((${index} + 1))
ndelta=$((${ndelta} + 1)) ndelta=$((${ndelta} + 1))
if [ ${psz} = "yes" ] ; then
npsizes=$((${npsizes} + 1))
fi
done done
# All remaining groups. # All remaining groups.
@@ -157,6 +183,9 @@ size_classes() {
# Final written value is correct: # Final written value is correct:
lookup_maxclass="((((size_t)1) << ${lg_grp}) + (((size_t)${ndelta}) << ${lg_delta}))" lookup_maxclass="((((size_t)1) << ${lg_grp}) + (((size_t)${ndelta}) << ${lg_delta}))"
fi fi
if [ ${psz} = "yes" ] ; then
npsizes=$((${npsizes} + 1))
fi
if [ ${bin} != "no" ] ; then if [ ${bin} != "no" ] ; then
nbins=$((${index} + 1)) nbins=$((${index} + 1))
# Final written value is correct: # Final written value is correct:
@@ -183,6 +212,7 @@ size_classes() {
# - nlbins # - nlbins
# - nbins # - nbins
# - nsizes # - nsizes
# - npsizes
# - lg_tiny_maxclass # - lg_tiny_maxclass
# - lookup_maxclass # - lookup_maxclass
# - small_maxclass # - small_maxclass
@@ -200,13 +230,13 @@ cat <<EOF
* be defined prior to inclusion, and it in turn defines: * be defined prior to inclusion, and it in turn defines:
* *
* LG_SIZE_CLASS_GROUP: Lg of size class count for each size doubling. * LG_SIZE_CLASS_GROUP: Lg of size class count for each size doubling.
* SIZE_CLASSES: Complete table of * SIZE_CLASSES: Complete table of SC(index, lg_grp, lg_delta, ndelta, psz,
* SC(index, lg_grp, lg_delta, ndelta, bin, lg_delta_lookup) * bin, lg_delta_lookup) tuples.
* tuples.
* index: Size class index. * index: Size class index.
* lg_grp: Lg group base size (no deltas added). * lg_grp: Lg group base size (no deltas added).
* lg_delta: Lg delta to previous size class. * lg_delta: Lg delta to previous size class.
* ndelta: Delta multiplier. size == 1<<lg_grp + ndelta<<lg_delta * ndelta: Delta multiplier. size == 1<<lg_grp + ndelta<<lg_delta
* psz: 'yes' if a multiple of the page size, 'no' otherwise.
* bin: 'yes' if a small bin size class, 'no' otherwise. * bin: 'yes' if a small bin size class, 'no' otherwise.
* lg_delta_lookup: Same as lg_delta if a lookup table size class, 'no' * lg_delta_lookup: Same as lg_delta if a lookup table size class, 'no'
* otherwise. * otherwise.
@@ -214,6 +244,7 @@ cat <<EOF
* NLBINS: Number of bins supported by the lookup table. * NLBINS: Number of bins supported by the lookup table.
* NBINS: Number of small size class bins. * NBINS: Number of small size class bins.
* NSIZES: Number of size classes. * NSIZES: Number of size classes.
* NPSIZES: Number of size classes that are a multiple of (1U << LG_PAGE).
* LG_TINY_MAXCLASS: Lg of maximum tiny size class. * LG_TINY_MAXCLASS: Lg of maximum tiny size class.
* LOOKUP_MAXCLASS: Maximum size class included in lookup table. * LOOKUP_MAXCLASS: Maximum size class included in lookup table.
* SMALL_MAXCLASS: Maximum small size class. * SMALL_MAXCLASS: Maximum small size class.
@@ -238,6 +269,7 @@ for lg_z in ${lg_zarr} ; do
echo "#define NLBINS ${nlbins}" echo "#define NLBINS ${nlbins}"
echo "#define NBINS ${nbins}" echo "#define NBINS ${nbins}"
echo "#define NSIZES ${nsizes}" echo "#define NSIZES ${nsizes}"
echo "#define NPSIZES ${npsizes}"
echo "#define LG_TINY_MAXCLASS ${lg_tiny_maxclass}" echo "#define LG_TINY_MAXCLASS ${lg_tiny_maxclass}"
echo "#define LOOKUP_MAXCLASS ${lookup_maxclass}" echo "#define LOOKUP_MAXCLASS ${lookup_maxclass}"
echo "#define SMALL_MAXCLASS ${small_maxclass}" echo "#define SMALL_MAXCLASS ${small_maxclass}"

View File

@@ -0,0 +1,51 @@
/******************************************************************************/
#ifdef JEMALLOC_H_TYPES
typedef struct spin_s spin_t;
#endif /* JEMALLOC_H_TYPES */
/******************************************************************************/
#ifdef JEMALLOC_H_STRUCTS
struct spin_s {
unsigned iteration;
};
#endif /* JEMALLOC_H_STRUCTS */
/******************************************************************************/
#ifdef JEMALLOC_H_EXTERNS
#endif /* JEMALLOC_H_EXTERNS */
/******************************************************************************/
#ifdef JEMALLOC_H_INLINES
#ifndef JEMALLOC_ENABLE_INLINE
void spin_init(spin_t *spin);
void spin_adaptive(spin_t *spin);
#endif
#if (defined(JEMALLOC_ENABLE_INLINE) || defined(JEMALLOC_SPIN_C_))
JEMALLOC_INLINE void
spin_init(spin_t *spin)
{
spin->iteration = 0;
}
JEMALLOC_INLINE void
spin_adaptive(spin_t *spin)
{
volatile uint64_t i;
for (i = 0; i < (KQU(1) << spin->iteration); i++)
CPU_SPINWAIT;
if (spin->iteration < 63)
spin->iteration++;
}
#endif
#endif /* JEMALLOC_H_INLINES */
/******************************************************************************/

View File

@@ -175,25 +175,21 @@ stats_cactive_get(void)
JEMALLOC_INLINE void JEMALLOC_INLINE void
stats_cactive_add(size_t size) stats_cactive_add(size_t size)
{ {
UNUSED size_t cactive;
assert(size > 0); assert(size > 0);
assert((size & chunksize_mask) == 0); assert((size & chunksize_mask) == 0);
cactive = atomic_add_z(&stats_cactive, size); atomic_add_z(&stats_cactive, size);
assert(cactive - size < cactive);
} }
JEMALLOC_INLINE void JEMALLOC_INLINE void
stats_cactive_sub(size_t size) stats_cactive_sub(size_t size)
{ {
UNUSED size_t cactive;
assert(size > 0); assert(size > 0);
assert((size & chunksize_mask) == 0); assert((size & chunksize_mask) == 0);
cactive = atomic_sub_z(&stats_cactive, size); atomic_sub_z(&stats_cactive, size);
assert(cactive + size > cactive);
} }
#endif #endif

View File

@@ -145,10 +145,13 @@ tcache_t *tcache_create(tsdn_t *tsdn, arena_t *arena);
void tcache_cleanup(tsd_t *tsd); void tcache_cleanup(tsd_t *tsd);
void tcache_enabled_cleanup(tsd_t *tsd); void tcache_enabled_cleanup(tsd_t *tsd);
void tcache_stats_merge(tsdn_t *tsdn, tcache_t *tcache, arena_t *arena); void tcache_stats_merge(tsdn_t *tsdn, tcache_t *tcache, arena_t *arena);
bool tcaches_create(tsdn_t *tsdn, unsigned *r_ind); bool tcaches_create(tsd_t *tsd, unsigned *r_ind);
void tcaches_flush(tsd_t *tsd, unsigned ind); void tcaches_flush(tsd_t *tsd, unsigned ind);
void tcaches_destroy(tsd_t *tsd, unsigned ind); void tcaches_destroy(tsd_t *tsd, unsigned ind);
bool tcache_boot(tsdn_t *tsdn); bool tcache_boot(tsdn_t *tsdn);
void tcache_prefork(tsdn_t *tsdn);
void tcache_postfork_parent(tsdn_t *tsdn);
void tcache_postfork_child(tsdn_t *tsdn);
#endif /* JEMALLOC_H_EXTERNS */ #endif /* JEMALLOC_H_EXTERNS */
/******************************************************************************/ /******************************************************************************/

View File

@@ -48,7 +48,7 @@ typedef enum {
* *
* bool example_tsd_boot(void) {...} * bool example_tsd_boot(void) {...}
* bool example_tsd_booted_get(void) {...} * bool example_tsd_booted_get(void) {...}
* example_t *example_tsd_get() {...} * example_t *example_tsd_get(bool init) {...}
* void example_tsd_set(example_t *val) {...} * void example_tsd_set(example_t *val) {...}
* *
* Note that all of the functions deal in terms of (a_type *) rather than * Note that all of the functions deal in terms of (a_type *) rather than
@@ -105,7 +105,7 @@ a_name##tsd_boot(void); \
a_attr bool \ a_attr bool \
a_name##tsd_booted_get(void); \ a_name##tsd_booted_get(void); \
a_attr a_type * \ a_attr a_type * \
a_name##tsd_get(void); \ a_name##tsd_get(bool init); \
a_attr void \ a_attr void \
a_name##tsd_set(a_type *val); a_name##tsd_set(a_type *val);
@@ -213,9 +213,15 @@ a_name##tsd_booted_get(void) \
\ \
return (a_name##tsd_booted); \ return (a_name##tsd_booted); \
} \ } \
a_attr bool \
a_name##tsd_get_allocates(void) \
{ \
\
return (false); \
} \
/* Get/set. */ \ /* Get/set. */ \
a_attr a_type * \ a_attr a_type * \
a_name##tsd_get(void) \ a_name##tsd_get(bool init) \
{ \ { \
\ \
assert(a_name##tsd_booted); \ assert(a_name##tsd_booted); \
@@ -264,9 +270,15 @@ a_name##tsd_booted_get(void) \
\ \
return (a_name##tsd_booted); \ return (a_name##tsd_booted); \
} \ } \
a_attr bool \
a_name##tsd_get_allocates(void) \
{ \
\
return (false); \
} \
/* Get/set. */ \ /* Get/set. */ \
a_attr a_type * \ a_attr a_type * \
a_name##tsd_get(void) \ a_name##tsd_get(bool init) \
{ \ { \
\ \
assert(a_name##tsd_booted); \ assert(a_name##tsd_booted); \
@@ -325,14 +337,14 @@ a_name##tsd_wrapper_set(a_name##tsd_wrapper_t *wrapper) \
} \ } \
} \ } \
a_attr a_name##tsd_wrapper_t * \ a_attr a_name##tsd_wrapper_t * \
a_name##tsd_wrapper_get(void) \ a_name##tsd_wrapper_get(bool init) \
{ \ { \
DWORD error = GetLastError(); \ DWORD error = GetLastError(); \
a_name##tsd_wrapper_t *wrapper = (a_name##tsd_wrapper_t *) \ a_name##tsd_wrapper_t *wrapper = (a_name##tsd_wrapper_t *) \
TlsGetValue(a_name##tsd_tsd); \ TlsGetValue(a_name##tsd_tsd); \
SetLastError(error); \ SetLastError(error); \
\ \
if (unlikely(wrapper == NULL)) { \ if (init && unlikely(wrapper == NULL)) { \
wrapper = (a_name##tsd_wrapper_t *) \ wrapper = (a_name##tsd_wrapper_t *) \
malloc_tsd_malloc(sizeof(a_name##tsd_wrapper_t)); \ malloc_tsd_malloc(sizeof(a_name##tsd_wrapper_t)); \
if (wrapper == NULL) { \ if (wrapper == NULL) { \
@@ -392,14 +404,22 @@ a_name##tsd_booted_get(void) \
\ \
return (a_name##tsd_booted); \ return (a_name##tsd_booted); \
} \ } \
a_attr bool \
a_name##tsd_get_allocates(void) \
{ \
\
return (true); \
} \
/* Get/set. */ \ /* Get/set. */ \
a_attr a_type * \ a_attr a_type * \
a_name##tsd_get(void) \ a_name##tsd_get(bool init) \
{ \ { \
a_name##tsd_wrapper_t *wrapper; \ a_name##tsd_wrapper_t *wrapper; \
\ \
assert(a_name##tsd_booted); \ assert(a_name##tsd_booted); \
wrapper = a_name##tsd_wrapper_get(); \ wrapper = a_name##tsd_wrapper_get(init); \
if (a_name##tsd_get_allocates() && !init && wrapper == NULL) \
return (NULL); \
return (&wrapper->val); \ return (&wrapper->val); \
} \ } \
a_attr void \ a_attr void \
@@ -408,7 +428,7 @@ a_name##tsd_set(a_type *val) \
a_name##tsd_wrapper_t *wrapper; \ a_name##tsd_wrapper_t *wrapper; \
\ \
assert(a_name##tsd_booted); \ assert(a_name##tsd_booted); \
wrapper = a_name##tsd_wrapper_get(); \ wrapper = a_name##tsd_wrapper_get(true); \
wrapper->val = *(val); \ wrapper->val = *(val); \
if (a_cleanup != malloc_tsd_no_cleanup) \ if (a_cleanup != malloc_tsd_no_cleanup) \
wrapper->initialized = true; \ wrapper->initialized = true; \
@@ -452,20 +472,21 @@ a_name##tsd_wrapper_set(a_name##tsd_wrapper_t *wrapper) \
} \ } \
} \ } \
a_attr a_name##tsd_wrapper_t * \ a_attr a_name##tsd_wrapper_t * \
a_name##tsd_wrapper_get(void) \ a_name##tsd_wrapper_get(bool init) \
{ \ { \
a_name##tsd_wrapper_t *wrapper = (a_name##tsd_wrapper_t *) \ a_name##tsd_wrapper_t *wrapper = (a_name##tsd_wrapper_t *) \
pthread_getspecific(a_name##tsd_tsd); \ pthread_getspecific(a_name##tsd_tsd); \
\ \
if (unlikely(wrapper == NULL)) { \ if (init && unlikely(wrapper == NULL)) { \
tsd_init_block_t block; \ tsd_init_block_t block; \
wrapper = tsd_init_check_recursion( \ wrapper = (a_name##tsd_wrapper_t *) \
&a_name##tsd_init_head, &block); \ tsd_init_check_recursion(&a_name##tsd_init_head, \
&block); \
if (wrapper) \ if (wrapper) \
return (wrapper); \ return (wrapper); \
wrapper = (a_name##tsd_wrapper_t *) \ wrapper = (a_name##tsd_wrapper_t *) \
malloc_tsd_malloc(sizeof(a_name##tsd_wrapper_t)); \ malloc_tsd_malloc(sizeof(a_name##tsd_wrapper_t)); \
block.data = wrapper; \ block.data = (void *)wrapper; \
if (wrapper == NULL) { \ if (wrapper == NULL) { \
malloc_write("<jemalloc>: Error allocating" \ malloc_write("<jemalloc>: Error allocating" \
" TSD for "#a_name"\n"); \ " TSD for "#a_name"\n"); \
@@ -520,14 +541,22 @@ a_name##tsd_booted_get(void) \
\ \
return (a_name##tsd_booted); \ return (a_name##tsd_booted); \
} \ } \
a_attr bool \
a_name##tsd_get_allocates(void) \
{ \
\
return (true); \
} \
/* Get/set. */ \ /* Get/set. */ \
a_attr a_type * \ a_attr a_type * \
a_name##tsd_get(void) \ a_name##tsd_get(bool init) \
{ \ { \
a_name##tsd_wrapper_t *wrapper; \ a_name##tsd_wrapper_t *wrapper; \
\ \
assert(a_name##tsd_booted); \ assert(a_name##tsd_booted); \
wrapper = a_name##tsd_wrapper_get(); \ wrapper = a_name##tsd_wrapper_get(init); \
if (a_name##tsd_get_allocates() && !init && wrapper == NULL) \
return (NULL); \
return (&wrapper->val); \ return (&wrapper->val); \
} \ } \
a_attr void \ a_attr void \
@@ -536,7 +565,7 @@ a_name##tsd_set(a_type *val) \
a_name##tsd_wrapper_t *wrapper; \ a_name##tsd_wrapper_t *wrapper; \
\ \
assert(a_name##tsd_booted); \ assert(a_name##tsd_booted); \
wrapper = a_name##tsd_wrapper_get(); \ wrapper = a_name##tsd_wrapper_get(true); \
wrapper->val = *(val); \ wrapper->val = *(val); \
if (a_cleanup != malloc_tsd_no_cleanup) \ if (a_cleanup != malloc_tsd_no_cleanup) \
wrapper->initialized = true; \ wrapper->initialized = true; \
@@ -639,6 +668,7 @@ void tsd_cleanup(void *arg);
#ifndef JEMALLOC_ENABLE_INLINE #ifndef JEMALLOC_ENABLE_INLINE
malloc_tsd_protos(JEMALLOC_ATTR(unused), , tsd_t) malloc_tsd_protos(JEMALLOC_ATTR(unused), , tsd_t)
tsd_t *tsd_fetch_impl(bool init);
tsd_t *tsd_fetch(void); tsd_t *tsd_fetch(void);
tsdn_t *tsd_tsdn(tsd_t *tsd); tsdn_t *tsd_tsdn(tsd_t *tsd);
bool tsd_nominal(tsd_t *tsd); bool tsd_nominal(tsd_t *tsd);
@@ -658,9 +688,13 @@ malloc_tsd_externs(, tsd_t)
malloc_tsd_funcs(JEMALLOC_ALWAYS_INLINE, , tsd_t, tsd_initializer, tsd_cleanup) malloc_tsd_funcs(JEMALLOC_ALWAYS_INLINE, , tsd_t, tsd_initializer, tsd_cleanup)
JEMALLOC_ALWAYS_INLINE tsd_t * JEMALLOC_ALWAYS_INLINE tsd_t *
tsd_fetch(void) tsd_fetch_impl(bool init)
{ {
tsd_t *tsd = tsd_get(); tsd_t *tsd = tsd_get(init);
if (!init && tsd_get_allocates() && tsd == NULL)
return (NULL);
assert(tsd != NULL);
if (unlikely(tsd->state != tsd_state_nominal)) { if (unlikely(tsd->state != tsd_state_nominal)) {
if (tsd->state == tsd_state_uninitialized) { if (tsd->state == tsd_state_uninitialized) {
@@ -677,6 +711,13 @@ tsd_fetch(void)
return (tsd); return (tsd);
} }
JEMALLOC_ALWAYS_INLINE tsd_t *
tsd_fetch(void)
{
return (tsd_fetch_impl(true));
}
JEMALLOC_ALWAYS_INLINE tsdn_t * JEMALLOC_ALWAYS_INLINE tsdn_t *
tsd_tsdn(tsd_t *tsd) tsd_tsdn(tsd_t *tsd)
{ {
@@ -723,7 +764,7 @@ tsdn_fetch(void)
if (!tsd_booted_get()) if (!tsd_booted_get())
return (NULL); return (NULL);
return (tsd_tsdn(tsd_fetch())); return (tsd_tsdn(tsd_fetch_impl(false)));
} }
JEMALLOC_ALWAYS_INLINE bool JEMALLOC_ALWAYS_INLINE bool

View File

@@ -41,8 +41,12 @@
#define MALLOC_PRINTF_BUFSIZE 4096 #define MALLOC_PRINTF_BUFSIZE 4096
/* Junk fill patterns. */ /* Junk fill patterns. */
#define JEMALLOC_ALLOC_JUNK ((uint8_t)0xa5) #ifndef JEMALLOC_ALLOC_JUNK
#define JEMALLOC_FREE_JUNK ((uint8_t)0x5a) # define JEMALLOC_ALLOC_JUNK ((uint8_t)0xa5)
#endif
#ifndef JEMALLOC_FREE_JUNK
# define JEMALLOC_FREE_JUNK ((uint8_t)0x5a)
#endif
/* /*
* Wrap a cpp argument that contains commas such that it isn't broken up into * Wrap a cpp argument that contains commas such that it isn't broken up into
@@ -61,30 +65,20 @@
# define JEMALLOC_CC_SILENCE_INIT(v) # define JEMALLOC_CC_SILENCE_INIT(v)
#endif #endif
#define JEMALLOC_GNUC_PREREQ(major, minor) \
(!defined(__clang__) && \
(__GNUC__ > (major) || (__GNUC__ == (major) && __GNUC_MINOR__ >= (minor))))
#ifndef __has_builtin
# define __has_builtin(builtin) (0)
#endif
#define JEMALLOC_CLANG_HAS_BUILTIN(builtin) \
(defined(__clang__) && __has_builtin(builtin))
#ifdef __GNUC__ #ifdef __GNUC__
# define likely(x) __builtin_expect(!!(x), 1) # define likely(x) __builtin_expect(!!(x), 1)
# define unlikely(x) __builtin_expect(!!(x), 0) # define unlikely(x) __builtin_expect(!!(x), 0)
# if JEMALLOC_GNUC_PREREQ(4, 6) || \
JEMALLOC_CLANG_HAS_BUILTIN(__builtin_unreachable)
# define unreachable() __builtin_unreachable()
# else
# define unreachable() abort()
# endif
#else #else
# define likely(x) !!(x) # define likely(x) !!(x)
# define unlikely(x) !!(x) # define unlikely(x) !!(x)
# define unreachable() abort()
#endif #endif
#if !defined(JEMALLOC_INTERNAL_UNREACHABLE)
# error JEMALLOC_INTERNAL_UNREACHABLE should have been defined by configure
#endif
#define unreachable() JEMALLOC_INTERNAL_UNREACHABLE()
#include "jemalloc/internal/assert.h" #include "jemalloc/internal/assert.h"
/* Use to assert a particular configuration, e.g., cassert(config_debug). */ /* Use to assert a particular configuration, e.g., cassert(config_debug). */

View File

@@ -36,13 +36,25 @@
zero); \ zero); \
} \ } \
} while (0) } while (0)
#define JEMALLOC_VALGRIND_REALLOC(maybe_moved, tsdn, ptr, usize, \ #define JEMALLOC_VALGRIND_REALLOC_MOVED_no(ptr, old_ptr) \
ptr_maybe_null, old_ptr, old_usize, old_rzsize, old_ptr_maybe_null, \ (false)
zero) do { \ #define JEMALLOC_VALGRIND_REALLOC_MOVED_maybe(ptr, old_ptr) \
((ptr) != (old_ptr))
#define JEMALLOC_VALGRIND_REALLOC_PTR_NULL_no(ptr) \
(false)
#define JEMALLOC_VALGRIND_REALLOC_PTR_NULL_maybe(ptr) \
(ptr == NULL)
#define JEMALLOC_VALGRIND_REALLOC_OLD_PTR_NULL_no(old_ptr) \
(false)
#define JEMALLOC_VALGRIND_REALLOC_OLD_PTR_NULL_maybe(old_ptr) \
(old_ptr == NULL)
#define JEMALLOC_VALGRIND_REALLOC(moved, tsdn, ptr, usize, ptr_null, \
old_ptr, old_usize, old_rzsize, old_ptr_null, zero) do { \
if (unlikely(in_valgrind)) { \ if (unlikely(in_valgrind)) { \
size_t rzsize = p2rz(tsdn, ptr); \ size_t rzsize = p2rz(tsdn, ptr); \
\ \
if (!maybe_moved || ptr == old_ptr) { \ if (!JEMALLOC_VALGRIND_REALLOC_MOVED_##moved(ptr, \
old_ptr)) { \
VALGRIND_RESIZEINPLACE_BLOCK(ptr, old_usize, \ VALGRIND_RESIZEINPLACE_BLOCK(ptr, old_usize, \
usize, rzsize); \ usize, rzsize); \
if (zero && old_usize < usize) { \ if (zero && old_usize < usize) { \
@@ -51,11 +63,13 @@
old_usize), usize - old_usize); \ old_usize), usize - old_usize); \
} \ } \
} else { \ } else { \
if (!old_ptr_maybe_null || old_ptr != NULL) { \ if (!JEMALLOC_VALGRIND_REALLOC_OLD_PTR_NULL_## \
old_ptr_null(old_ptr)) { \
valgrind_freelike_block(old_ptr, \ valgrind_freelike_block(old_ptr, \
old_rzsize); \ old_rzsize); \
} \ } \
if (!ptr_maybe_null || ptr != NULL) { \ if (!JEMALLOC_VALGRIND_REALLOC_PTR_NULL_## \
ptr_null(ptr)) { \
size_t copy_size = (old_usize < usize) \ size_t copy_size = (old_usize < usize) \
? old_usize : usize; \ ? old_usize : usize; \
size_t tail_size = usize - copy_size; \ size_t tail_size = usize - copy_size; \

View File

@@ -12,21 +12,32 @@ typedef int witness_comp_t (const witness_t *, const witness_t *);
*/ */
#define WITNESS_RANK_OMIT 0U #define WITNESS_RANK_OMIT 0U
#define WITNESS_RANK_MIN 1U
#define WITNESS_RANK_INIT 1U #define WITNESS_RANK_INIT 1U
#define WITNESS_RANK_CTL 1U #define WITNESS_RANK_CTL 1U
#define WITNESS_RANK_ARENAS 2U #define WITNESS_RANK_TCACHES 2U
#define WITNESS_RANK_ARENAS 3U
#define WITNESS_RANK_PROF_DUMP 3U #define WITNESS_RANK_PROF_DUMP 4U
#define WITNESS_RANK_PROF_BT2GCTX 4U #define WITNESS_RANK_PROF_BT2GCTX 5U
#define WITNESS_RANK_PROF_TDATAS 5U #define WITNESS_RANK_PROF_TDATAS 6U
#define WITNESS_RANK_PROF_TDATA 6U #define WITNESS_RANK_PROF_TDATA 7U
#define WITNESS_RANK_PROF_GCTX 7U #define WITNESS_RANK_PROF_GCTX 8U
#define WITNESS_RANK_ARENA 8U /*
#define WITNESS_RANK_ARENA_CHUNKS 9U * Used as an argument to witness_assert_depth_to_rank() in order to validate
#define WITNESS_RANK_ARENA_NODE_CACHE 10 * depth excluding non-core locks with lower ranks. Since the rank argument to
* witness_assert_depth_to_rank() is inclusive rather than exclusive, this
* definition can have the same value as the minimally ranked core lock.
*/
#define WITNESS_RANK_CORE 9U
#define WITNESS_RANK_BASE 11U #define WITNESS_RANK_ARENA 9U
#define WITNESS_RANK_ARENA_CHUNKS 10U
#define WITNESS_RANK_ARENA_NODE_CACHE 11U
#define WITNESS_RANK_BASE 12U
#define WITNESS_RANK_LEAF 0xffffffffU #define WITNESS_RANK_LEAF 0xffffffffU
#define WITNESS_RANK_ARENA_BIN WITNESS_RANK_LEAF #define WITNESS_RANK_ARENA_BIN WITNESS_RANK_LEAF
@@ -91,10 +102,12 @@ extern witness_not_owner_error_t *witness_not_owner_error;
void witness_not_owner_error(const witness_t *witness); void witness_not_owner_error(const witness_t *witness);
#endif #endif
#ifdef JEMALLOC_JET #ifdef JEMALLOC_JET
typedef void (witness_lockless_error_t)(const witness_list_t *); typedef void (witness_depth_error_t)(const witness_list_t *,
extern witness_lockless_error_t *witness_lockless_error; witness_rank_t rank_inclusive, unsigned depth);
extern witness_depth_error_t *witness_depth_error;
#else #else
void witness_lockless_error(const witness_list_t *witnesses); void witness_depth_error(const witness_list_t *witnesses,
witness_rank_t rank_inclusive, unsigned depth);
#endif #endif
void witnesses_cleanup(tsd_t *tsd); void witnesses_cleanup(tsd_t *tsd);
@@ -108,20 +121,39 @@ void witness_postfork_child(tsd_t *tsd);
#ifdef JEMALLOC_H_INLINES #ifdef JEMALLOC_H_INLINES
#ifndef JEMALLOC_ENABLE_INLINE #ifndef JEMALLOC_ENABLE_INLINE
bool witness_owner(tsd_t *tsd, const witness_t *witness);
void witness_assert_owner(tsdn_t *tsdn, const witness_t *witness); void witness_assert_owner(tsdn_t *tsdn, const witness_t *witness);
void witness_assert_not_owner(tsdn_t *tsdn, const witness_t *witness); void witness_assert_not_owner(tsdn_t *tsdn, const witness_t *witness);
void witness_assert_depth_to_rank(tsdn_t *tsdn, witness_rank_t rank_inclusive,
unsigned depth);
void witness_assert_depth(tsdn_t *tsdn, unsigned depth);
void witness_assert_lockless(tsdn_t *tsdn); void witness_assert_lockless(tsdn_t *tsdn);
void witness_lock(tsdn_t *tsdn, witness_t *witness); void witness_lock(tsdn_t *tsdn, witness_t *witness);
void witness_unlock(tsdn_t *tsdn, witness_t *witness); void witness_unlock(tsdn_t *tsdn, witness_t *witness);
#endif #endif
#if (defined(JEMALLOC_ENABLE_INLINE) || defined(JEMALLOC_MUTEX_C_)) #if (defined(JEMALLOC_ENABLE_INLINE) || defined(JEMALLOC_MUTEX_C_))
JEMALLOC_INLINE bool
witness_owner(tsd_t *tsd, const witness_t *witness)
{
witness_list_t *witnesses;
witness_t *w;
cassert(config_debug);
witnesses = tsd_witnessesp_get(tsd);
ql_foreach(w, witnesses, link) {
if (w == witness)
return (true);
}
return (false);
}
JEMALLOC_INLINE void JEMALLOC_INLINE void
witness_assert_owner(tsdn_t *tsdn, const witness_t *witness) witness_assert_owner(tsdn_t *tsdn, const witness_t *witness)
{ {
tsd_t *tsd; tsd_t *tsd;
witness_list_t *witnesses;
witness_t *w;
if (!config_debug) if (!config_debug)
return; return;
@@ -132,11 +164,8 @@ witness_assert_owner(tsdn_t *tsdn, const witness_t *witness)
if (witness->rank == WITNESS_RANK_OMIT) if (witness->rank == WITNESS_RANK_OMIT)
return; return;
witnesses = tsd_witnessesp_get(tsd); if (witness_owner(tsd, witness))
ql_foreach(w, witnesses, link) { return;
if (w == witness)
return;
}
witness_owner_error(witness); witness_owner_error(witness);
} }
@@ -164,9 +193,10 @@ witness_assert_not_owner(tsdn_t *tsdn, const witness_t *witness)
} }
JEMALLOC_INLINE void JEMALLOC_INLINE void
witness_assert_lockless(tsdn_t *tsdn) witness_assert_depth_to_rank(tsdn_t *tsdn, witness_rank_t rank_inclusive,
{ unsigned depth) {
tsd_t *tsd; tsd_t *tsd;
unsigned d;
witness_list_t *witnesses; witness_list_t *witnesses;
witness_t *w; witness_t *w;
@@ -177,10 +207,29 @@ witness_assert_lockless(tsdn_t *tsdn)
return; return;
tsd = tsdn_tsd(tsdn); tsd = tsdn_tsd(tsdn);
d = 0;
witnesses = tsd_witnessesp_get(tsd); witnesses = tsd_witnessesp_get(tsd);
w = ql_last(witnesses, link); w = ql_last(witnesses, link);
if (w != NULL) if (w != NULL) {
witness_lockless_error(witnesses); ql_reverse_foreach(w, witnesses, link) {
if (w->rank < rank_inclusive) {
break;
}
d++;
}
}
if (d != depth)
witness_depth_error(witnesses, rank_inclusive, depth);
}
JEMALLOC_INLINE void
witness_assert_depth(tsdn_t *tsdn, unsigned depth) {
witness_assert_depth_to_rank(tsdn, WITNESS_RANK_MIN, depth);
}
JEMALLOC_INLINE void
witness_assert_lockless(tsdn_t *tsdn) {
witness_assert_depth(tsdn, 0);
} }
JEMALLOC_INLINE void JEMALLOC_INLINE void
@@ -238,10 +287,16 @@ witness_unlock(tsdn_t *tsdn, witness_t *witness)
if (witness->rank == WITNESS_RANK_OMIT) if (witness->rank == WITNESS_RANK_OMIT)
return; return;
witness_assert_owner(tsdn, witness); /*
* Check whether owner before removal, rather than relying on
witnesses = tsd_witnessesp_get(tsd); * witness_assert_owner() to abort, so that unit tests can test this
ql_remove(witnesses, witness, link); * function's failure mode without causing undefined behavior.
*/
if (witness_owner(tsd, witness)) {
witnesses = tsd_witnessesp_get(tsd);
ql_remove(witnesses, witness, link);
} else
witness_assert_owner(tsdn, witness);
} }
#endif #endif

View File

@@ -6,7 +6,7 @@ install_suffix=@install_suffix@
Name: jemalloc Name: jemalloc
Description: A general purpose malloc(3) implementation that emphasizes fragmentation avoidance and scalable concurrency support. Description: A general purpose malloc(3) implementation that emphasizes fragmentation avoidance and scalable concurrency support.
URL: http://www.canonware.com/jemalloc URL: http://jemalloc.net/
Version: @jemalloc_version@ Version: @jemalloc_version@
Cflags: -I${includedir} Cflags: -I${includedir}
Libs: -L${libdir} -ljemalloc${install_suffix} Libs: -L${libdir} -ljemalloc${install_suffix}

View File

@@ -17,7 +17,7 @@ How to build jemalloc for Windows
(note: x86/x64 doesn't matter at this point) (note: x86/x64 doesn't matter at this point)
5. Generate header files: 5. Generate header files:
sh -c "./autogen.sh CC=cl --enable-lazy-lock=no" sh -c "CC=cl ./autogen.sh"
6. Now the project can be opened and built in Visual Studio: 6. Now the project can be opened and built in Visual Studio:
msvc\jemalloc_vc2015.sln msvc\jemalloc_vc2015.sln

View File

@@ -69,12 +69,14 @@
<ClInclude Include="..\..\..\..\include\jemalloc\internal\rb.h" /> <ClInclude Include="..\..\..\..\include\jemalloc\internal\rb.h" />
<ClInclude Include="..\..\..\..\include\jemalloc\internal\rtree.h" /> <ClInclude Include="..\..\..\..\include\jemalloc\internal\rtree.h" />
<ClInclude Include="..\..\..\..\include\jemalloc\internal\size_classes.h" /> <ClInclude Include="..\..\..\..\include\jemalloc\internal\size_classes.h" />
<ClInclude Include="..\..\..\..\include\jemalloc\internal\smoothstep.h" />
<ClInclude Include="..\..\..\..\include\jemalloc\internal\spin.h" />
<ClInclude Include="..\..\..\..\include\jemalloc\internal\stats.h" /> <ClInclude Include="..\..\..\..\include\jemalloc\internal\stats.h" />
<ClInclude Include="..\..\..\..\include\jemalloc\internal\tcache.h" /> <ClInclude Include="..\..\..\..\include\jemalloc\internal\tcache.h" />
<ClInclude Include="..\..\..\..\include\jemalloc\internal\ticker.h" /> <ClInclude Include="..\..\..\..\include\jemalloc\internal\ticker.h" />
<ClInclude Include="..\..\..\..\include\jemalloc\internal\tsd.h" /> <ClInclude Include="..\..\..\..\include\jemalloc\internal\tsd.h" />
<ClInclude Include="..\..\..\..\include\jemalloc\internal\util.h" /> <ClInclude Include="..\..\..\..\include\jemalloc\internal\util.h" />
<ClInclude Include="..\..\..\..\include\jemalloc\internal\valgrind.h" /> <ClInclude Include="..\..\..\..\include\jemalloc\internal\witness.h" />
<ClInclude Include="..\..\..\..\include\jemalloc\jemalloc.h" /> <ClInclude Include="..\..\..\..\include\jemalloc\jemalloc.h" />
<ClInclude Include="..\..\..\..\include\jemalloc\jemalloc_defs.h" /> <ClInclude Include="..\..\..\..\include\jemalloc\jemalloc_defs.h" />
<ClInclude Include="..\..\..\..\include\jemalloc\jemalloc_macros.h" /> <ClInclude Include="..\..\..\..\include\jemalloc\jemalloc_macros.h" />
@@ -110,11 +112,13 @@
<ClCompile Include="..\..\..\..\src\prof.c" /> <ClCompile Include="..\..\..\..\src\prof.c" />
<ClCompile Include="..\..\..\..\src\quarantine.c" /> <ClCompile Include="..\..\..\..\src\quarantine.c" />
<ClCompile Include="..\..\..\..\src\rtree.c" /> <ClCompile Include="..\..\..\..\src\rtree.c" />
<ClCompile Include="..\..\..\..\src\spin.c" />
<ClCompile Include="..\..\..\..\src\stats.c" /> <ClCompile Include="..\..\..\..\src\stats.c" />
<ClCompile Include="..\..\..\..\src\tcache.c" /> <ClCompile Include="..\..\..\..\src\tcache.c" />
<ClCompile Include="..\..\..\..\src\ticker.c" /> <ClCompile Include="..\..\..\..\src\ticker.c" />
<ClCompile Include="..\..\..\..\src\tsd.c" /> <ClCompile Include="..\..\..\..\src\tsd.c" />
<ClCompile Include="..\..\..\..\src\util.c" /> <ClCompile Include="..\..\..\..\src\util.c" />
<ClCompile Include="..\..\..\..\src\witness.c" />
</ItemGroup> </ItemGroup>
<PropertyGroup Label="Globals"> <PropertyGroup Label="Globals">
<ProjectGuid>{8D6BB292-9E1C-413D-9F98-4864BDC1514A}</ProjectGuid> <ProjectGuid>{8D6BB292-9E1C-413D-9F98-4864BDC1514A}</ProjectGuid>

View File

@@ -146,6 +146,12 @@
<ClInclude Include="..\..\..\..\include\jemalloc\internal\size_classes.h"> <ClInclude Include="..\..\..\..\include\jemalloc\internal\size_classes.h">
<Filter>Header Files\internal</Filter> <Filter>Header Files\internal</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="..\..\..\..\include\jemalloc\internal\smoothstep.h">
<Filter>Header Files\internal</Filter>
</ClInclude>
<ClInclude Include="..\..\..\..\include\jemalloc\internal\spin.h">
<Filter>Header Files\internal</Filter>
</ClInclude>
<ClInclude Include="..\..\..\..\include\jemalloc\internal\stats.h"> <ClInclude Include="..\..\..\..\include\jemalloc\internal\stats.h">
<Filter>Header Files\internal</Filter> <Filter>Header Files\internal</Filter>
</ClInclude> </ClInclude>
@@ -161,7 +167,7 @@
<ClInclude Include="..\..\..\..\include\jemalloc\internal\util.h"> <ClInclude Include="..\..\..\..\include\jemalloc\internal\util.h">
<Filter>Header Files\internal</Filter> <Filter>Header Files\internal</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="..\..\..\..\include\jemalloc\internal\valgrind.h"> <ClInclude Include="..\..\..\..\include\jemalloc\internal\witness.h">
<Filter>Header Files\internal</Filter> <Filter>Header Files\internal</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="..\..\..\..\include\msvc_compat\strings.h"> <ClInclude Include="..\..\..\..\include\msvc_compat\strings.h">
@@ -241,6 +247,9 @@
<ClCompile Include="..\..\..\..\src\rtree.c"> <ClCompile Include="..\..\..\..\src\rtree.c">
<Filter>Source Files</Filter> <Filter>Source Files</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="..\..\..\..\src\spin.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\..\..\src\stats.c"> <ClCompile Include="..\..\..\..\src\stats.c">
<Filter>Source Files</Filter> <Filter>Source Files</Filter>
</ClCompile> </ClCompile>
@@ -256,5 +265,8 @@
<ClCompile Include="..\..\..\..\src\util.c"> <ClCompile Include="..\..\..\..\src\util.c">
<Filter>Source Files</Filter> <Filter>Source Files</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="..\..\..\..\src\witness.c">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup> </ItemGroup>
</Project> </Project>

View File

@@ -21,7 +21,7 @@ int test_threads()
je_malloc_conf = "narenas:3"; je_malloc_conf = "narenas:3";
int narenas = 0; int narenas = 0;
size_t sz = sizeof(narenas); size_t sz = sizeof(narenas);
je_mallctl("opt.narenas", &narenas, &sz, NULL, 0); je_mallctl("opt.narenas", (void *)&narenas, &sz, NULL, 0);
if (narenas != 3) { if (narenas != 3) {
printf("Error: unexpected number of arenas: %d\n", narenas); printf("Error: unexpected number of arenas: %d\n", narenas);
return 1; return 1;
@@ -33,7 +33,7 @@ int test_threads()
je_malloc_stats_print(NULL, NULL, NULL); je_malloc_stats_print(NULL, NULL, NULL);
size_t allocated1; size_t allocated1;
size_t sz1 = sizeof(allocated1); size_t sz1 = sizeof(allocated1);
je_mallctl("stats.active", &allocated1, &sz1, NULL, 0); je_mallctl("stats.active", (void *)&allocated1, &sz1, NULL, 0);
printf("\nPress Enter to start threads...\n"); printf("\nPress Enter to start threads...\n");
getchar(); getchar();
printf("Starting %d threads x %d x %d iterations...\n", numThreads, numIter1, numIter2); printf("Starting %d threads x %d x %d iterations...\n", numThreads, numIter1, numIter2);
@@ -78,7 +78,7 @@ int test_threads()
} }
je_malloc_stats_print(NULL, NULL, NULL); je_malloc_stats_print(NULL, NULL, NULL);
size_t allocated2; size_t allocated2;
je_mallctl("stats.active", &allocated2, &sz1, NULL, 0); je_mallctl("stats.active", (void *)&allocated2, &sz1, NULL, 0);
size_t leaked = allocated2 - allocated1; size_t leaked = allocated2 - allocated1;
printf("\nDone. Leaked: %zd bytes\n", leaked); printf("\nDone. Leaked: %zd bytes\n", leaked);
bool failed = leaked > 65536; // in case C++ runtime allocated something (e.g. iostream locale or facet) bool failed = leaked > 65536; // in case C++ runtime allocated something (e.g. iostream locale or facet)

85
scripts/gen_travis.py Executable file
View File

@@ -0,0 +1,85 @@
#!/usr/bin/env python
from itertools import combinations
travis_template = """\
language: generic
matrix:
include:
%s
before_script:
- autoconf
- ./configure ${COMPILER_FLAGS:+ \
CC="$CC $COMPILER_FLAGS" } \
$CONFIGURE_FLAGS
- make -j3
- make -j3 tests
script:
- make check
"""
# The 'default' configuration is gcc, on linux, with no compiler or configure
# flags. We also test with clang, -m32, --enable-debug, --enable-prof,
# --disable-stats, and --disable-tcache. To avoid abusing travis though, we
# don't test all 2**7 = 128 possible combinations of these; instead, we only
# test combinations of up to 2 'unusual' settings, under the hope that bugs
# involving interactions of such settings are rare.
# things at once, for C(7, 0) + C(7, 1) + C(7, 2) = 29
MAX_UNUSUAL_OPTIONS = 2
os_default = 'linux'
os_unusual = 'osx'
compilers_default = 'CC=gcc'
compilers_unusual = 'CC=clang'
compiler_flag_unusuals = ['-m32']
configure_flag_unusuals = [
'--enable-debug', '--enable-prof', '--disable-stats', '--disable-tcache',
]
all_unusuals = (
[os_unusual] + [compilers_unusual] + compiler_flag_unusuals
+ configure_flag_unusuals
)
unusual_combinations_to_test = []
for i in xrange(MAX_UNUSUAL_OPTIONS + 1):
unusual_combinations_to_test += combinations(all_unusuals, i)
include_rows = ""
for unusual_combination in unusual_combinations_to_test:
os = os_default
if os_unusual in unusual_combination:
os = os_unusual
compilers = compilers_default
if compilers_unusual in unusual_combination:
compilers = compilers_unusual
compiler_flags = [
x for x in unusual_combination if x in compiler_flag_unusuals]
configure_flags = [
x for x in unusual_combination if x in configure_flag_unusuals]
# Filter out an unsupported configuration - heap profiling on OS X.
if os == 'osx' and '--enable-prof' in configure_flags:
continue
env_string = '{} COMPILER_FLAGS="{}" CONFIGURE_FLAGS="{}"'.format(
compilers, " ".join(compiler_flags), " ".join(configure_flags))
include_rows += ' - os: %s\n' % os
include_rows += ' env: %s\n' % env_string
if '-m32' in unusual_combination and os == 'linux':
include_rows += ' addons:\n'
include_rows += ' apt:\n'
include_rows += ' packages:\n'
include_rows += ' - gcc-multilib\n'
print travis_template % include_rows

File diff suppressed because it is too large Load Diff

View File

@@ -5,7 +5,8 @@
/* Data. */ /* Data. */
static malloc_mutex_t base_mtx; static malloc_mutex_t base_mtx;
static extent_tree_t base_avail_szad; static size_t base_extent_sn_next;
static extent_tree_t base_avail_szsnad;
static extent_node_t *base_nodes; static extent_node_t *base_nodes;
static size_t base_allocated; static size_t base_allocated;
static size_t base_resident; static size_t base_resident;
@@ -39,6 +40,14 @@ base_node_dalloc(tsdn_t *tsdn, extent_node_t *node)
base_nodes = node; base_nodes = node;
} }
static void
base_extent_node_init(extent_node_t *node, void *addr, size_t size)
{
size_t sn = atomic_add_z(&base_extent_sn_next, 1) - 1;
extent_node_init(node, NULL, addr, size, sn, true, true);
}
static extent_node_t * static extent_node_t *
base_chunk_alloc(tsdn_t *tsdn, size_t minsize) base_chunk_alloc(tsdn_t *tsdn, size_t minsize)
{ {
@@ -68,7 +77,7 @@ base_chunk_alloc(tsdn_t *tsdn, size_t minsize)
base_resident += PAGE_CEILING(nsize); base_resident += PAGE_CEILING(nsize);
} }
} }
extent_node_init(node, NULL, addr, csize, true, true); base_extent_node_init(node, addr, csize);
return (node); return (node);
} }
@@ -92,12 +101,12 @@ base_alloc(tsdn_t *tsdn, size_t size)
csize = CACHELINE_CEILING(size); csize = CACHELINE_CEILING(size);
usize = s2u(csize); usize = s2u(csize);
extent_node_init(&key, NULL, NULL, usize, false, false); extent_node_init(&key, NULL, NULL, usize, 0, false, false);
malloc_mutex_lock(tsdn, &base_mtx); malloc_mutex_lock(tsdn, &base_mtx);
node = extent_tree_szad_nsearch(&base_avail_szad, &key); node = extent_tree_szsnad_nsearch(&base_avail_szsnad, &key);
if (node != NULL) { if (node != NULL) {
/* Use existing space. */ /* Use existing space. */
extent_tree_szad_remove(&base_avail_szad, node); extent_tree_szsnad_remove(&base_avail_szsnad, node);
} else { } else {
/* Try to allocate more space. */ /* Try to allocate more space. */
node = base_chunk_alloc(tsdn, csize); node = base_chunk_alloc(tsdn, csize);
@@ -111,7 +120,7 @@ base_alloc(tsdn_t *tsdn, size_t size)
if (extent_node_size_get(node) > csize) { if (extent_node_size_get(node) > csize) {
extent_node_addr_set(node, (void *)((uintptr_t)ret + csize)); extent_node_addr_set(node, (void *)((uintptr_t)ret + csize));
extent_node_size_set(node, extent_node_size_get(node) - csize); extent_node_size_set(node, extent_node_size_get(node) - csize);
extent_tree_szad_insert(&base_avail_szad, node); extent_tree_szsnad_insert(&base_avail_szsnad, node);
} else } else
base_node_dalloc(tsdn, node); base_node_dalloc(tsdn, node);
if (config_stats) { if (config_stats) {
@@ -149,7 +158,8 @@ base_boot(void)
if (malloc_mutex_init(&base_mtx, "base", WITNESS_RANK_BASE)) if (malloc_mutex_init(&base_mtx, "base", WITNESS_RANK_BASE))
return (true); return (true);
extent_tree_szad_new(&base_avail_szad); base_extent_sn_next = 0;
extent_tree_szsnad_new(&base_avail_szsnad);
base_nodes = NULL; base_nodes = NULL;
return (false); return (false);

View File

@@ -50,9 +50,9 @@ const chunk_hooks_t chunk_hooks_default = {
*/ */
static void chunk_record(tsdn_t *tsdn, arena_t *arena, static void chunk_record(tsdn_t *tsdn, arena_t *arena,
chunk_hooks_t *chunk_hooks, extent_tree_t *chunks_szad, chunk_hooks_t *chunk_hooks, extent_tree_t *chunks_szsnad,
extent_tree_t *chunks_ad, bool cache, void *chunk, size_t size, bool zeroed, extent_tree_t *chunks_ad, bool cache, void *chunk, size_t size, size_t sn,
bool committed); bool zeroed, bool committed);
/******************************************************************************/ /******************************************************************************/
@@ -141,7 +141,7 @@ chunk_hooks_assure_initialized(tsdn_t *tsdn, arena_t *arena,
} }
bool bool
chunk_register(tsdn_t *tsdn, const void *chunk, const extent_node_t *node) chunk_register(const void *chunk, const extent_node_t *node, bool *gdump)
{ {
assert(extent_node_addr_get(node) == chunk); assert(extent_node_addr_get(node) == chunk);
@@ -160,8 +160,7 @@ chunk_register(tsdn_t *tsdn, const void *chunk, const extent_node_t *node)
*/ */
high = atomic_read_z(&highchunks); high = atomic_read_z(&highchunks);
} }
if (cur > high && prof_gdump_get_unlocked()) *gdump = (cur > high && prof_gdump_get_unlocked());
prof_gdump(tsdn);
} }
return (false); return (false);
@@ -183,33 +182,40 @@ chunk_deregister(const void *chunk, const extent_node_t *node)
} }
/* /*
* Do first-best-fit chunk selection, i.e. select the lowest chunk that best * Do first-best-fit chunk selection, i.e. select the oldest/lowest chunk that
* fits. * best fits.
*/ */
static extent_node_t * static extent_node_t *
chunk_first_best_fit(arena_t *arena, extent_tree_t *chunks_szad, chunk_first_best_fit(arena_t *arena, extent_tree_t *chunks_szsnad, size_t size)
extent_tree_t *chunks_ad, size_t size)
{ {
extent_node_t *node;
size_t qsize;
extent_node_t key; extent_node_t key;
assert(size == CHUNK_CEILING(size)); assert(size == CHUNK_CEILING(size));
extent_node_init(&key, arena, NULL, size, false, false); qsize = extent_size_quantize_ceil(size);
return (extent_tree_szad_nsearch(chunks_szad, &key)); extent_node_init(&key, arena, NULL, qsize, 0, false, false);
node = extent_tree_szsnad_nsearch(chunks_szsnad, &key);
assert(node == NULL || extent_node_size_get(node) >= size);
return node;
} }
static void * static void *
chunk_recycle(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, chunk_recycle(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks,
extent_tree_t *chunks_szad, extent_tree_t *chunks_ad, bool cache, extent_tree_t *chunks_szsnad, extent_tree_t *chunks_ad, bool cache,
void *new_addr, size_t size, size_t alignment, bool *zero, bool *commit, void *new_addr, size_t size, size_t alignment, size_t *sn, bool *zero,
bool dalloc_node) bool *commit, bool dalloc_node)
{ {
void *ret; void *ret;
extent_node_t *node; extent_node_t *node;
size_t alloc_size, leadsize, trailsize; size_t alloc_size, leadsize, trailsize;
bool zeroed, committed; bool zeroed, committed;
assert(CHUNK_CEILING(size) == size);
assert(alignment > 0);
assert(new_addr == NULL || alignment == chunksize); assert(new_addr == NULL || alignment == chunksize);
assert(CHUNK_ADDR2BASE(new_addr) == new_addr);
/* /*
* Cached chunks use the node linkage embedded in their headers, in * Cached chunks use the node linkage embedded in their headers, in
* which case dalloc_node is true, and new_addr is non-NULL because * which case dalloc_node is true, and new_addr is non-NULL because
@@ -217,7 +223,7 @@ chunk_recycle(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks,
*/ */
assert(dalloc_node || new_addr != NULL); assert(dalloc_node || new_addr != NULL);
alloc_size = CHUNK_CEILING(s2u(size + alignment - chunksize)); alloc_size = size + CHUNK_CEILING(alignment) - chunksize;
/* Beware size_t wrap-around. */ /* Beware size_t wrap-around. */
if (alloc_size < size) if (alloc_size < size)
return (NULL); return (NULL);
@@ -225,12 +231,11 @@ chunk_recycle(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks,
chunk_hooks_assure_initialized_locked(tsdn, arena, chunk_hooks); chunk_hooks_assure_initialized_locked(tsdn, arena, chunk_hooks);
if (new_addr != NULL) { if (new_addr != NULL) {
extent_node_t key; extent_node_t key;
extent_node_init(&key, arena, new_addr, alloc_size, false, extent_node_init(&key, arena, new_addr, alloc_size, 0, false,
false); false);
node = extent_tree_ad_search(chunks_ad, &key); node = extent_tree_ad_search(chunks_ad, &key);
} else { } else {
node = chunk_first_best_fit(arena, chunks_szad, chunks_ad, node = chunk_first_best_fit(arena, chunks_szsnad, alloc_size);
alloc_size);
} }
if (node == NULL || (new_addr != NULL && extent_node_size_get(node) < if (node == NULL || (new_addr != NULL && extent_node_size_get(node) <
size)) { size)) {
@@ -243,10 +248,11 @@ chunk_recycle(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks,
assert(extent_node_size_get(node) >= leadsize + size); assert(extent_node_size_get(node) >= leadsize + size);
trailsize = extent_node_size_get(node) - leadsize - size; trailsize = extent_node_size_get(node) - leadsize - size;
ret = (void *)((uintptr_t)extent_node_addr_get(node) + leadsize); ret = (void *)((uintptr_t)extent_node_addr_get(node) + leadsize);
*sn = extent_node_sn_get(node);
zeroed = extent_node_zeroed_get(node); zeroed = extent_node_zeroed_get(node);
if (zeroed)
*zero = true;
committed = extent_node_committed_get(node); committed = extent_node_committed_get(node);
if (zeroed && committed)
*zero = true;
if (committed) if (committed)
*commit = true; *commit = true;
/* Split the lead. */ /* Split the lead. */
@@ -257,13 +263,13 @@ chunk_recycle(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks,
return (NULL); return (NULL);
} }
/* Remove node from the tree. */ /* Remove node from the tree. */
extent_tree_szad_remove(chunks_szad, node); extent_tree_szsnad_remove(chunks_szsnad, node);
extent_tree_ad_remove(chunks_ad, node); extent_tree_ad_remove(chunks_ad, node);
arena_chunk_cache_maybe_remove(arena, node, cache); arena_chunk_cache_maybe_remove(arena, node, cache);
if (leadsize != 0) { if (leadsize != 0) {
/* Insert the leading space as a smaller chunk. */ /* Insert the leading space as a smaller chunk. */
extent_node_size_set(node, leadsize); extent_node_size_set(node, leadsize);
extent_tree_szad_insert(chunks_szad, node); extent_tree_szsnad_insert(chunks_szsnad, node);
extent_tree_ad_insert(chunks_ad, node); extent_tree_ad_insert(chunks_ad, node);
arena_chunk_cache_maybe_insert(arena, node, cache); arena_chunk_cache_maybe_insert(arena, node, cache);
node = NULL; node = NULL;
@@ -275,9 +281,9 @@ chunk_recycle(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks,
if (dalloc_node && node != NULL) if (dalloc_node && node != NULL)
arena_node_dalloc(tsdn, arena, node); arena_node_dalloc(tsdn, arena, node);
malloc_mutex_unlock(tsdn, &arena->chunks_mtx); malloc_mutex_unlock(tsdn, &arena->chunks_mtx);
chunk_record(tsdn, arena, chunk_hooks, chunks_szad, chunk_record(tsdn, arena, chunk_hooks, chunks_szsnad,
chunks_ad, cache, ret, size + trailsize, zeroed, chunks_ad, cache, ret, size + trailsize, *sn,
committed); zeroed, committed);
return (NULL); return (NULL);
} }
/* Insert the trailing space as a smaller chunk. */ /* Insert the trailing space as a smaller chunk. */
@@ -286,22 +292,23 @@ chunk_recycle(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks,
if (node == NULL) { if (node == NULL) {
malloc_mutex_unlock(tsdn, &arena->chunks_mtx); malloc_mutex_unlock(tsdn, &arena->chunks_mtx);
chunk_record(tsdn, arena, chunk_hooks, chunk_record(tsdn, arena, chunk_hooks,
chunks_szad, chunks_ad, cache, ret, size + chunks_szsnad, chunks_ad, cache, ret, size
trailsize, zeroed, committed); + trailsize, *sn, zeroed, committed);
return (NULL); return (NULL);
} }
} }
extent_node_init(node, arena, (void *)((uintptr_t)(ret) + size), extent_node_init(node, arena, (void *)((uintptr_t)(ret) + size),
trailsize, zeroed, committed); trailsize, *sn, zeroed, committed);
extent_tree_szad_insert(chunks_szad, node); extent_tree_szsnad_insert(chunks_szsnad, node);
extent_tree_ad_insert(chunks_ad, node); extent_tree_ad_insert(chunks_ad, node);
arena_chunk_cache_maybe_insert(arena, node, cache); arena_chunk_cache_maybe_insert(arena, node, cache);
node = NULL; node = NULL;
} }
if (!committed && chunk_hooks->commit(ret, size, 0, size, arena->ind)) { if (*commit && !committed && chunk_hooks->commit(ret, size, 0, size,
arena->ind)) {
malloc_mutex_unlock(tsdn, &arena->chunks_mtx); malloc_mutex_unlock(tsdn, &arena->chunks_mtx);
chunk_record(tsdn, arena, chunk_hooks, chunks_szad, chunks_ad, chunk_record(tsdn, arena, chunk_hooks, chunks_szsnad, chunks_ad,
cache, ret, size, zeroed, committed); cache, ret, size, *sn, zeroed, committed);
return (NULL); return (NULL);
} }
malloc_mutex_unlock(tsdn, &arena->chunks_mtx); malloc_mutex_unlock(tsdn, &arena->chunks_mtx);
@@ -316,10 +323,11 @@ chunk_recycle(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks,
size_t i; size_t i;
size_t *p = (size_t *)(uintptr_t)ret; size_t *p = (size_t *)(uintptr_t)ret;
JEMALLOC_VALGRIND_MAKE_MEM_DEFINED(ret, size);
for (i = 0; i < size / sizeof(size_t); i++) for (i = 0; i < size / sizeof(size_t); i++)
assert(p[i] == 0); assert(p[i] == 0);
} }
if (config_valgrind)
JEMALLOC_VALGRIND_MAKE_MEM_DEFINED(ret, size);
} }
return (ret); return (ret);
} }
@@ -384,23 +392,21 @@ chunk_alloc_base(size_t size)
void * void *
chunk_alloc_cache(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, chunk_alloc_cache(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks,
void *new_addr, size_t size, size_t alignment, bool *zero, bool dalloc_node) void *new_addr, size_t size, size_t alignment, size_t *sn, bool *zero,
bool *commit, bool dalloc_node)
{ {
void *ret; void *ret;
bool commit;
assert(size != 0); assert(size != 0);
assert((size & chunksize_mask) == 0); assert((size & chunksize_mask) == 0);
assert(alignment != 0); assert(alignment != 0);
assert((alignment & chunksize_mask) == 0); assert((alignment & chunksize_mask) == 0);
commit = true;
ret = chunk_recycle(tsdn, arena, chunk_hooks, ret = chunk_recycle(tsdn, arena, chunk_hooks,
&arena->chunks_szad_cached, &arena->chunks_ad_cached, true, &arena->chunks_szsnad_cached, &arena->chunks_ad_cached, true,
new_addr, size, alignment, zero, &commit, dalloc_node); new_addr, size, alignment, sn, zero, commit, dalloc_node);
if (ret == NULL) if (ret == NULL)
return (NULL); return (NULL);
assert(commit);
if (config_valgrind) if (config_valgrind)
JEMALLOC_VALGRIND_MAKE_MEM_UNDEFINED(ret, size); JEMALLOC_VALGRIND_MAKE_MEM_UNDEFINED(ret, size);
return (ret); return (ret);
@@ -421,15 +427,11 @@ chunk_arena_get(tsdn_t *tsdn, unsigned arena_ind)
} }
static void * static void *
chunk_alloc_default(void *new_addr, size_t size, size_t alignment, bool *zero, chunk_alloc_default_impl(tsdn_t *tsdn, arena_t *arena, void *new_addr,
bool *commit, unsigned arena_ind) size_t size, size_t alignment, bool *zero, bool *commit)
{ {
void *ret; void *ret;
tsdn_t *tsdn;
arena_t *arena;
tsdn = tsdn_fetch();
arena = chunk_arena_get(tsdn, arena_ind);
ret = chunk_alloc_core(tsdn, arena, new_addr, size, alignment, zero, ret = chunk_alloc_core(tsdn, arena, new_addr, size, alignment, zero,
commit, arena->dss_prec); commit, arena->dss_prec);
if (ret == NULL) if (ret == NULL)
@@ -440,9 +442,24 @@ chunk_alloc_default(void *new_addr, size_t size, size_t alignment, bool *zero,
return (ret); return (ret);
} }
static void *
chunk_alloc_default(void *new_addr, size_t size, size_t alignment, bool *zero,
bool *commit, unsigned arena_ind)
{
tsdn_t *tsdn;
arena_t *arena;
tsdn = tsdn_fetch();
arena = chunk_arena_get(tsdn, arena_ind);
return (chunk_alloc_default_impl(tsdn, arena, new_addr, size, alignment,
zero, commit));
}
static void * static void *
chunk_alloc_retained(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, chunk_alloc_retained(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks,
void *new_addr, size_t size, size_t alignment, bool *zero, bool *commit) void *new_addr, size_t size, size_t alignment, size_t *sn, bool *zero,
bool *commit)
{ {
void *ret; void *ret;
@@ -452,8 +469,8 @@ chunk_alloc_retained(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks,
assert((alignment & chunksize_mask) == 0); assert((alignment & chunksize_mask) == 0);
ret = chunk_recycle(tsdn, arena, chunk_hooks, ret = chunk_recycle(tsdn, arena, chunk_hooks,
&arena->chunks_szad_retained, &arena->chunks_ad_retained, false, &arena->chunks_szsnad_retained, &arena->chunks_ad_retained, false,
new_addr, size, alignment, zero, commit, true); new_addr, size, alignment, sn, zero, commit, true);
if (config_stats && ret != NULL) if (config_stats && ret != NULL)
arena->stats.retained -= size; arena->stats.retained -= size;
@@ -463,30 +480,42 @@ chunk_alloc_retained(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks,
void * void *
chunk_alloc_wrapper(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, chunk_alloc_wrapper(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks,
void *new_addr, size_t size, size_t alignment, bool *zero, bool *commit) void *new_addr, size_t size, size_t alignment, size_t *sn, bool *zero,
bool *commit)
{ {
void *ret; void *ret;
chunk_hooks_assure_initialized(tsdn, arena, chunk_hooks); chunk_hooks_assure_initialized(tsdn, arena, chunk_hooks);
ret = chunk_alloc_retained(tsdn, arena, chunk_hooks, new_addr, size, ret = chunk_alloc_retained(tsdn, arena, chunk_hooks, new_addr, size,
alignment, zero, commit); alignment, sn, zero, commit);
if (ret == NULL) { if (ret == NULL) {
ret = chunk_hooks->alloc(new_addr, size, alignment, zero, if (chunk_hooks->alloc == chunk_alloc_default) {
commit, arena->ind); /* Call directly to propagate tsdn. */
ret = chunk_alloc_default_impl(tsdn, arena, new_addr,
size, alignment, zero, commit);
} else {
ret = chunk_hooks->alloc(new_addr, size, alignment,
zero, commit, arena->ind);
}
if (ret == NULL) if (ret == NULL)
return (NULL); return (NULL);
*sn = arena_extent_sn_next(arena);
if (config_valgrind && chunk_hooks->alloc !=
chunk_alloc_default)
JEMALLOC_VALGRIND_MAKE_MEM_UNDEFINED(ret, chunksize);
} }
if (config_valgrind && chunk_hooks->alloc != chunk_alloc_default)
JEMALLOC_VALGRIND_MAKE_MEM_UNDEFINED(ret, chunksize);
return (ret); return (ret);
} }
static void static void
chunk_record(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, chunk_record(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks,
extent_tree_t *chunks_szad, extent_tree_t *chunks_ad, bool cache, extent_tree_t *chunks_szsnad, extent_tree_t *chunks_ad, bool cache,
void *chunk, size_t size, bool zeroed, bool committed) void *chunk, size_t size, size_t sn, bool zeroed, bool committed)
{ {
bool unzeroed; bool unzeroed;
extent_node_t *node, *prev; extent_node_t *node, *prev;
@@ -498,7 +527,7 @@ chunk_record(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks,
malloc_mutex_lock(tsdn, &arena->chunks_mtx); malloc_mutex_lock(tsdn, &arena->chunks_mtx);
chunk_hooks_assure_initialized_locked(tsdn, arena, chunk_hooks); chunk_hooks_assure_initialized_locked(tsdn, arena, chunk_hooks);
extent_node_init(&key, arena, (void *)((uintptr_t)chunk + size), 0, extent_node_init(&key, arena, (void *)((uintptr_t)chunk + size), 0, 0,
false, false); false, false);
node = extent_tree_ad_nsearch(chunks_ad, &key); node = extent_tree_ad_nsearch(chunks_ad, &key);
/* Try to coalesce forward. */ /* Try to coalesce forward. */
@@ -510,15 +539,17 @@ chunk_record(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks,
/* /*
* Coalesce chunk with the following address range. This does * Coalesce chunk with the following address range. This does
* not change the position within chunks_ad, so only * not change the position within chunks_ad, so only
* remove/insert from/into chunks_szad. * remove/insert from/into chunks_szsnad.
*/ */
extent_tree_szad_remove(chunks_szad, node); extent_tree_szsnad_remove(chunks_szsnad, node);
arena_chunk_cache_maybe_remove(arena, node, cache); arena_chunk_cache_maybe_remove(arena, node, cache);
extent_node_addr_set(node, chunk); extent_node_addr_set(node, chunk);
extent_node_size_set(node, size + extent_node_size_get(node)); extent_node_size_set(node, size + extent_node_size_get(node));
if (sn < extent_node_sn_get(node))
extent_node_sn_set(node, sn);
extent_node_zeroed_set(node, extent_node_zeroed_get(node) && extent_node_zeroed_set(node, extent_node_zeroed_get(node) &&
!unzeroed); !unzeroed);
extent_tree_szad_insert(chunks_szad, node); extent_tree_szsnad_insert(chunks_szsnad, node);
arena_chunk_cache_maybe_insert(arena, node, cache); arena_chunk_cache_maybe_insert(arena, node, cache);
} else { } else {
/* Coalescing forward failed, so insert a new node. */ /* Coalescing forward failed, so insert a new node. */
@@ -536,10 +567,10 @@ chunk_record(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks,
} }
goto label_return; goto label_return;
} }
extent_node_init(node, arena, chunk, size, !unzeroed, extent_node_init(node, arena, chunk, size, sn, !unzeroed,
committed); committed);
extent_tree_ad_insert(chunks_ad, node); extent_tree_ad_insert(chunks_ad, node);
extent_tree_szad_insert(chunks_szad, node); extent_tree_szsnad_insert(chunks_szsnad, node);
arena_chunk_cache_maybe_insert(arena, node, cache); arena_chunk_cache_maybe_insert(arena, node, cache);
} }
@@ -553,19 +584,21 @@ chunk_record(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks,
/* /*
* Coalesce chunk with the previous address range. This does * Coalesce chunk with the previous address range. This does
* not change the position within chunks_ad, so only * not change the position within chunks_ad, so only
* remove/insert node from/into chunks_szad. * remove/insert node from/into chunks_szsnad.
*/ */
extent_tree_szad_remove(chunks_szad, prev); extent_tree_szsnad_remove(chunks_szsnad, prev);
extent_tree_ad_remove(chunks_ad, prev); extent_tree_ad_remove(chunks_ad, prev);
arena_chunk_cache_maybe_remove(arena, prev, cache); arena_chunk_cache_maybe_remove(arena, prev, cache);
extent_tree_szad_remove(chunks_szad, node); extent_tree_szsnad_remove(chunks_szsnad, node);
arena_chunk_cache_maybe_remove(arena, node, cache); arena_chunk_cache_maybe_remove(arena, node, cache);
extent_node_addr_set(node, extent_node_addr_get(prev)); extent_node_addr_set(node, extent_node_addr_get(prev));
extent_node_size_set(node, extent_node_size_get(prev) + extent_node_size_set(node, extent_node_size_get(prev) +
extent_node_size_get(node)); extent_node_size_get(node));
if (extent_node_sn_get(prev) < extent_node_sn_get(node))
extent_node_sn_set(node, extent_node_sn_get(prev));
extent_node_zeroed_set(node, extent_node_zeroed_get(prev) && extent_node_zeroed_set(node, extent_node_zeroed_get(prev) &&
extent_node_zeroed_get(node)); extent_node_zeroed_get(node));
extent_tree_szad_insert(chunks_szad, node); extent_tree_szsnad_insert(chunks_szsnad, node);
arena_chunk_cache_maybe_insert(arena, node, cache); arena_chunk_cache_maybe_insert(arena, node, cache);
arena_node_dalloc(tsdn, arena, prev); arena_node_dalloc(tsdn, arena, prev);
@@ -577,7 +610,7 @@ label_return:
void void
chunk_dalloc_cache(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, chunk_dalloc_cache(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks,
void *chunk, size_t size, bool committed) void *chunk, size_t size, size_t sn, bool committed)
{ {
assert(chunk != NULL); assert(chunk != NULL);
@@ -585,25 +618,34 @@ chunk_dalloc_cache(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks,
assert(size != 0); assert(size != 0);
assert((size & chunksize_mask) == 0); assert((size & chunksize_mask) == 0);
chunk_record(tsdn, arena, chunk_hooks, &arena->chunks_szad_cached, chunk_record(tsdn, arena, chunk_hooks, &arena->chunks_szsnad_cached,
&arena->chunks_ad_cached, true, chunk, size, false, committed); &arena->chunks_ad_cached, true, chunk, size, sn, false,
committed);
arena_maybe_purge(tsdn, arena); arena_maybe_purge(tsdn, arena);
} }
static bool
chunk_dalloc_default_impl(void *chunk, size_t size)
{
if (!have_dss || !chunk_in_dss(chunk))
return (chunk_dalloc_mmap(chunk, size));
return (true);
}
static bool static bool
chunk_dalloc_default(void *chunk, size_t size, bool committed, chunk_dalloc_default(void *chunk, size_t size, bool committed,
unsigned arena_ind) unsigned arena_ind)
{ {
if (!have_dss || !chunk_in_dss(tsdn_fetch(), chunk)) return (chunk_dalloc_default_impl(chunk, size));
return (chunk_dalloc_mmap(chunk, size));
return (true);
} }
void void
chunk_dalloc_wrapper(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, chunk_dalloc_wrapper(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks,
void *chunk, size_t size, bool zeroed, bool committed) void *chunk, size_t size, size_t sn, bool zeroed, bool committed)
{ {
bool err;
assert(chunk != NULL); assert(chunk != NULL);
assert(CHUNK_ADDR2BASE(chunk) == chunk); assert(CHUNK_ADDR2BASE(chunk) == chunk);
@@ -612,7 +654,13 @@ chunk_dalloc_wrapper(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks,
chunk_hooks_assure_initialized(tsdn, arena, chunk_hooks); chunk_hooks_assure_initialized(tsdn, arena, chunk_hooks);
/* Try to deallocate. */ /* Try to deallocate. */
if (!chunk_hooks->dalloc(chunk, size, committed, arena->ind)) if (chunk_hooks->dalloc == chunk_dalloc_default) {
/* Call directly to propagate tsdn. */
err = chunk_dalloc_default_impl(chunk, size);
} else
err = chunk_hooks->dalloc(chunk, size, committed, arena->ind);
if (!err)
return; return;
/* Try to decommit; purge if that fails. */ /* Try to decommit; purge if that fails. */
if (committed) { if (committed) {
@@ -621,8 +669,9 @@ chunk_dalloc_wrapper(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks,
} }
zeroed = !committed || !chunk_hooks->purge(chunk, size, 0, size, zeroed = !committed || !chunk_hooks->purge(chunk, size, 0, size,
arena->ind); arena->ind);
chunk_record(tsdn, arena, chunk_hooks, &arena->chunks_szad_retained, chunk_record(tsdn, arena, chunk_hooks, &arena->chunks_szsnad_retained,
&arena->chunks_ad_retained, false, chunk, size, zeroed, committed); &arena->chunks_ad_retained, false, chunk, size, sn, zeroed,
committed);
if (config_stats) if (config_stats)
arena->stats.retained += size; arena->stats.retained += size;
@@ -681,26 +730,30 @@ chunk_split_default(void *chunk, size_t size, size_t size_a, size_t size_b,
} }
static bool static bool
chunk_merge_default(void *chunk_a, size_t size_a, void *chunk_b, size_t size_b, chunk_merge_default_impl(void *chunk_a, void *chunk_b)
bool committed, unsigned arena_ind)
{ {
if (!maps_coalesce) if (!maps_coalesce)
return (true); return (true);
if (have_dss) { if (have_dss && !chunk_dss_mergeable(chunk_a, chunk_b))
tsdn_t *tsdn = tsdn_fetch(); return (true);
if (chunk_in_dss(tsdn, chunk_a) != chunk_in_dss(tsdn, chunk_b))
return (true);
}
return (false); return (false);
} }
static bool
chunk_merge_default(void *chunk_a, size_t size_a, void *chunk_b, size_t size_b,
bool committed, unsigned arena_ind)
{
return (chunk_merge_default_impl(chunk_a, chunk_b));
}
static rtree_node_elm_t * static rtree_node_elm_t *
chunks_rtree_node_alloc(size_t nelms) chunks_rtree_node_alloc(size_t nelms)
{ {
return ((rtree_node_elm_t *)base_alloc(tsdn_fetch(), nelms * return ((rtree_node_elm_t *)base_alloc(TSDN_NULL, nelms *
sizeof(rtree_node_elm_t))); sizeof(rtree_node_elm_t)));
} }
@@ -737,32 +790,11 @@ chunk_boot(void)
chunksize_mask = chunksize - 1; chunksize_mask = chunksize - 1;
chunk_npages = (chunksize >> LG_PAGE); chunk_npages = (chunksize >> LG_PAGE);
if (have_dss && chunk_dss_boot()) if (have_dss)
return (true); chunk_dss_boot();
if (rtree_new(&chunks_rtree, (unsigned)((ZU(1) << (LG_SIZEOF_PTR+3)) - if (rtree_new(&chunks_rtree, (unsigned)((ZU(1) << (LG_SIZEOF_PTR+3)) -
opt_lg_chunk), chunks_rtree_node_alloc, NULL)) opt_lg_chunk), chunks_rtree_node_alloc, NULL))
return (true); return (true);
return (false); return (false);
} }
void
chunk_prefork(tsdn_t *tsdn)
{
chunk_dss_prefork(tsdn);
}
void
chunk_postfork_parent(tsdn_t *tsdn)
{
chunk_dss_postfork_parent(tsdn);
}
void
chunk_postfork_child(tsdn_t *tsdn)
{
chunk_dss_postfork_child(tsdn);
}

View File

@@ -10,20 +10,21 @@ const char *dss_prec_names[] = {
"N/A" "N/A"
}; };
/* Current dss precedence default, used when creating new arenas. */
static dss_prec_t dss_prec_default = DSS_PREC_DEFAULT;
/* /*
* Protects sbrk() calls. This avoids malloc races among threads, though it * Current dss precedence default, used when creating new arenas. NB: This is
* does not protect against races with threads that call sbrk() directly. * stored as unsigned rather than dss_prec_t because in principle there's no
* guarantee that sizeof(dss_prec_t) is the same as sizeof(unsigned), and we use
* atomic operations to synchronize the setting.
*/ */
static malloc_mutex_t dss_mtx; static unsigned dss_prec_default = (unsigned)DSS_PREC_DEFAULT;
/* Base address of the DSS. */ /* Base address of the DSS. */
static void *dss_base; static void *dss_base;
/* Current end of the DSS, or ((void *)-1) if the DSS is exhausted. */ /* Atomic boolean indicating whether a thread is currently extending DSS. */
static void *dss_prev; static unsigned dss_extending;
/* Current upper limit on DSS addresses. */ /* Atomic boolean indicating whether the DSS is exhausted. */
static unsigned dss_exhausted;
/* Atomic current upper limit on DSS addresses. */
static void *dss_max; static void *dss_max;
/******************************************************************************/ /******************************************************************************/
@@ -41,30 +42,63 @@ chunk_dss_sbrk(intptr_t increment)
} }
dss_prec_t dss_prec_t
chunk_dss_prec_get(tsdn_t *tsdn) chunk_dss_prec_get(void)
{ {
dss_prec_t ret; dss_prec_t ret;
if (!have_dss) if (!have_dss)
return (dss_prec_disabled); return (dss_prec_disabled);
malloc_mutex_lock(tsdn, &dss_mtx); ret = (dss_prec_t)atomic_read_u(&dss_prec_default);
ret = dss_prec_default;
malloc_mutex_unlock(tsdn, &dss_mtx);
return (ret); return (ret);
} }
bool bool
chunk_dss_prec_set(tsdn_t *tsdn, dss_prec_t dss_prec) chunk_dss_prec_set(dss_prec_t dss_prec)
{ {
if (!have_dss) if (!have_dss)
return (dss_prec != dss_prec_disabled); return (dss_prec != dss_prec_disabled);
malloc_mutex_lock(tsdn, &dss_mtx); atomic_write_u(&dss_prec_default, (unsigned)dss_prec);
dss_prec_default = dss_prec;
malloc_mutex_unlock(tsdn, &dss_mtx);
return (false); return (false);
} }
static void *
chunk_dss_max_update(void *new_addr)
{
void *max_cur = chunk_dss_sbrk(0);
if (max_cur == (void *)-1) {
return NULL;
}
atomic_write_p(&dss_max, max_cur);
/* Fixed new_addr can only be supported if it is at the edge of DSS. */
if (new_addr != NULL && max_cur != new_addr)
return (NULL);
return (max_cur);
}
static void
chunk_dss_extending_start(void) {
spin_t spinner;
spin_init(&spinner);
while (true) {
unsigned expected = 0;
if (!atomic_cas_u(&dss_extending, expected, 1)) {
break;
}
spin_adaptive(&spinner);
}
}
static void
chunk_dss_extending_finish(void) {
assert(atomic_read_u(&dss_extending));
atomic_write_u(&dss_extending, 0);
}
void * void *
chunk_alloc_dss(tsdn_t *tsdn, arena_t *arena, void *new_addr, size_t size, chunk_alloc_dss(tsdn_t *tsdn, arena_t *arena, void *new_addr, size_t size,
size_t alignment, bool *zero, bool *commit) size_t alignment, bool *zero, bool *commit)
@@ -80,63 +114,67 @@ chunk_alloc_dss(tsdn_t *tsdn, arena_t *arena, void *new_addr, size_t size,
if ((intptr_t)size < 0) if ((intptr_t)size < 0)
return (NULL); return (NULL);
malloc_mutex_lock(tsdn, &dss_mtx); chunk_dss_extending_start();
if (dss_prev != (void *)-1) { if (!atomic_read_u(&dss_exhausted)) {
/* /*
* The loop is necessary to recover from races with other * The loop is necessary to recover from races with other
* threads that are using the DSS for something other than * threads that are using the DSS for something other than
* malloc. * malloc.
*/ */
do { while (true) {
void *ret, *cpad, *dss_next; void *ret, *max_cur, *dss_next, *dss_prev;
size_t gap_size, cpad_size; void *gap_addr_chunk, *gap_addr_subchunk;
size_t gap_size_chunk, gap_size_subchunk;
intptr_t incr; intptr_t incr;
/* Avoid an unnecessary system call. */
if (new_addr != NULL && dss_max != new_addr)
break;
/* Get the current end of the DSS. */ max_cur = chunk_dss_max_update(new_addr);
dss_max = chunk_dss_sbrk(0); if (max_cur == NULL)
goto label_oom;
/* Make sure the earlier condition still holds. */
if (new_addr != NULL && dss_max != new_addr)
break;
/* /*
* Calculate how much padding is necessary to * Compute how much chunk-aligned gap space (if any) is
* chunk-align the end of the DSS.
*/
gap_size = (chunksize - CHUNK_ADDR2OFFSET(dss_max)) &
chunksize_mask;
/*
* Compute how much chunk-aligned pad space (if any) is
* necessary to satisfy alignment. This space can be * necessary to satisfy alignment. This space can be
* recycled for later use. * recycled for later use.
*/ */
cpad = (void *)((uintptr_t)dss_max + gap_size); gap_addr_chunk = (void *)(CHUNK_CEILING(
ret = (void *)ALIGNMENT_CEILING((uintptr_t)dss_max, (uintptr_t)max_cur));
alignment); ret = (void *)ALIGNMENT_CEILING(
cpad_size = (uintptr_t)ret - (uintptr_t)cpad; (uintptr_t)gap_addr_chunk, alignment);
gap_size_chunk = (uintptr_t)ret -
(uintptr_t)gap_addr_chunk;
/*
* Compute the address just past the end of the desired
* allocation space.
*/
dss_next = (void *)((uintptr_t)ret + size); dss_next = (void *)((uintptr_t)ret + size);
if ((uintptr_t)ret < (uintptr_t)dss_max || if ((uintptr_t)ret < (uintptr_t)max_cur ||
(uintptr_t)dss_next < (uintptr_t)dss_max) { (uintptr_t)dss_next < (uintptr_t)max_cur)
/* Wrap-around. */ goto label_oom; /* Wrap-around. */
malloc_mutex_unlock(tsdn, &dss_mtx); /* Compute the increment, including subchunk bytes. */
return (NULL); gap_addr_subchunk = max_cur;
} gap_size_subchunk = (uintptr_t)ret -
incr = gap_size + cpad_size + size; (uintptr_t)gap_addr_subchunk;
incr = gap_size_subchunk + size;
assert((uintptr_t)max_cur + incr == (uintptr_t)ret +
size);
/* Try to allocate. */
dss_prev = chunk_dss_sbrk(incr); dss_prev = chunk_dss_sbrk(incr);
if (dss_prev == dss_max) { if (dss_prev == max_cur) {
/* Success. */ /* Success. */
dss_max = dss_next;
malloc_mutex_unlock(tsdn, &dss_mtx); atomic_write_p(&dss_max, dss_next);
if (cpad_size != 0) { chunk_dss_extending_finish();
if (gap_size_chunk != 0) {
chunk_hooks_t chunk_hooks = chunk_hooks_t chunk_hooks =
CHUNK_HOOKS_INITIALIZER; CHUNK_HOOKS_INITIALIZER;
chunk_dalloc_wrapper(tsdn, arena, chunk_dalloc_wrapper(tsdn, arena,
&chunk_hooks, cpad, cpad_size, &chunk_hooks, gap_addr_chunk,
false, true); gap_size_chunk,
arena_extent_sn_next(arena), false,
true);
} }
if (*zero) { if (*zero) {
JEMALLOC_VALGRIND_MAKE_MEM_UNDEFINED( JEMALLOC_VALGRIND_MAKE_MEM_UNDEFINED(
@@ -147,68 +185,62 @@ chunk_alloc_dss(tsdn_t *tsdn, arena_t *arena, void *new_addr, size_t size,
*commit = pages_decommit(ret, size); *commit = pages_decommit(ret, size);
return (ret); return (ret);
} }
} while (dss_prev != (void *)-1);
}
malloc_mutex_unlock(tsdn, &dss_mtx);
/*
* Failure, whether due to OOM or a race with a raw
* sbrk() call from outside the allocator.
*/
if (dss_prev == (void *)-1) {
/* OOM. */
atomic_write_u(&dss_exhausted, (unsigned)true);
goto label_oom;
}
}
}
label_oom:
chunk_dss_extending_finish();
return (NULL); return (NULL);
} }
bool static bool
chunk_in_dss(tsdn_t *tsdn, void *chunk) chunk_in_dss_helper(void *chunk, void *max)
{ {
bool ret;
cassert(have_dss); return ((uintptr_t)chunk >= (uintptr_t)dss_base && (uintptr_t)chunk <
(uintptr_t)max);
malloc_mutex_lock(tsdn, &dss_mtx);
if ((uintptr_t)chunk >= (uintptr_t)dss_base
&& (uintptr_t)chunk < (uintptr_t)dss_max)
ret = true;
else
ret = false;
malloc_mutex_unlock(tsdn, &dss_mtx);
return (ret);
} }
bool bool
chunk_in_dss(void *chunk)
{
cassert(have_dss);
return (chunk_in_dss_helper(chunk, atomic_read_p(&dss_max)));
}
bool
chunk_dss_mergeable(void *chunk_a, void *chunk_b)
{
void *max;
cassert(have_dss);
max = atomic_read_p(&dss_max);
return (chunk_in_dss_helper(chunk_a, max) ==
chunk_in_dss_helper(chunk_b, max));
}
void
chunk_dss_boot(void) chunk_dss_boot(void)
{ {
cassert(have_dss); cassert(have_dss);
if (malloc_mutex_init(&dss_mtx, "dss", WITNESS_RANK_DSS))
return (true);
dss_base = chunk_dss_sbrk(0); dss_base = chunk_dss_sbrk(0);
dss_prev = dss_base; atomic_write_u(&dss_extending, 0);
dss_exhausted = (unsigned)(dss_base == (void *)-1);
dss_max = dss_base; dss_max = dss_base;
return (false);
}
void
chunk_dss_prefork(tsdn_t *tsdn)
{
if (have_dss)
malloc_mutex_prefork(tsdn, &dss_mtx);
}
void
chunk_dss_postfork_parent(tsdn_t *tsdn)
{
if (have_dss)
malloc_mutex_postfork_parent(tsdn, &dss_mtx);
}
void
chunk_dss_postfork_child(tsdn_t *tsdn)
{
if (have_dss)
malloc_mutex_postfork_child(tsdn, &dss_mtx);
} }
/******************************************************************************/ /******************************************************************************/

View File

@@ -9,7 +9,7 @@ chunk_alloc_mmap_slow(size_t size, size_t alignment, bool *zero, bool *commit)
void *ret; void *ret;
size_t alloc_size; size_t alloc_size;
alloc_size = size + alignment; alloc_size = size + alignment - PAGE;
/* Beware size_t wrap-around. */ /* Beware size_t wrap-around. */
if (alloc_size < size) if (alloc_size < size)
return (NULL); return (NULL);

View File

@@ -40,8 +40,8 @@
/******************************************************************************/ /******************************************************************************/
/* Function prototypes for non-inline static functions. */ /* Function prototypes for non-inline static functions. */
static bool ckh_grow(tsdn_t *tsdn, ckh_t *ckh); static bool ckh_grow(tsd_t *tsd, ckh_t *ckh);
static void ckh_shrink(tsdn_t *tsdn, ckh_t *ckh); static void ckh_shrink(tsd_t *tsd, ckh_t *ckh);
/******************************************************************************/ /******************************************************************************/
@@ -99,7 +99,8 @@ ckh_try_bucket_insert(ckh_t *ckh, size_t bucket, const void *key,
* Cycle through the cells in the bucket, starting at a random position. * Cycle through the cells in the bucket, starting at a random position.
* The randomness avoids worst-case search overhead as buckets fill up. * The randomness avoids worst-case search overhead as buckets fill up.
*/ */
offset = (unsigned)prng_lg_range(&ckh->prng_state, LG_CKH_BUCKET_CELLS); offset = (unsigned)prng_lg_range_u64(&ckh->prng_state,
LG_CKH_BUCKET_CELLS);
for (i = 0; i < (ZU(1) << LG_CKH_BUCKET_CELLS); i++) { for (i = 0; i < (ZU(1) << LG_CKH_BUCKET_CELLS); i++) {
cell = &ckh->tab[(bucket << LG_CKH_BUCKET_CELLS) + cell = &ckh->tab[(bucket << LG_CKH_BUCKET_CELLS) +
((i + offset) & ((ZU(1) << LG_CKH_BUCKET_CELLS) - 1))]; ((i + offset) & ((ZU(1) << LG_CKH_BUCKET_CELLS) - 1))];
@@ -141,7 +142,7 @@ ckh_evict_reloc_insert(ckh_t *ckh, size_t argbucket, void const **argkey,
* were an item for which both hashes indicated the same * were an item for which both hashes indicated the same
* bucket. * bucket.
*/ */
i = (unsigned)prng_lg_range(&ckh->prng_state, i = (unsigned)prng_lg_range_u64(&ckh->prng_state,
LG_CKH_BUCKET_CELLS); LG_CKH_BUCKET_CELLS);
cell = &ckh->tab[(bucket << LG_CKH_BUCKET_CELLS) + i]; cell = &ckh->tab[(bucket << LG_CKH_BUCKET_CELLS) + i];
assert(cell->key != NULL); assert(cell->key != NULL);
@@ -244,7 +245,7 @@ ckh_rebuild(ckh_t *ckh, ckhc_t *aTab)
} }
static bool static bool
ckh_grow(tsdn_t *tsdn, ckh_t *ckh) ckh_grow(tsd_t *tsd, ckh_t *ckh)
{ {
bool ret; bool ret;
ckhc_t *tab, *ttab; ckhc_t *tab, *ttab;
@@ -270,8 +271,8 @@ ckh_grow(tsdn_t *tsdn, ckh_t *ckh)
ret = true; ret = true;
goto label_return; goto label_return;
} }
tab = (ckhc_t *)ipallocztm(tsdn, usize, CACHELINE, true, NULL, tab = (ckhc_t *)ipallocztm(tsd_tsdn(tsd), usize, CACHELINE,
true, arena_ichoose(tsdn, NULL)); true, NULL, true, arena_ichoose(tsd, NULL));
if (tab == NULL) { if (tab == NULL) {
ret = true; ret = true;
goto label_return; goto label_return;
@@ -283,12 +284,12 @@ ckh_grow(tsdn_t *tsdn, ckh_t *ckh)
ckh->lg_curbuckets = lg_curcells - LG_CKH_BUCKET_CELLS; ckh->lg_curbuckets = lg_curcells - LG_CKH_BUCKET_CELLS;
if (!ckh_rebuild(ckh, tab)) { if (!ckh_rebuild(ckh, tab)) {
idalloctm(tsdn, tab, NULL, true, true); idalloctm(tsd_tsdn(tsd), tab, NULL, true, true);
break; break;
} }
/* Rebuilding failed, so back out partially rebuilt table. */ /* Rebuilding failed, so back out partially rebuilt table. */
idalloctm(tsdn, ckh->tab, NULL, true, true); idalloctm(tsd_tsdn(tsd), ckh->tab, NULL, true, true);
ckh->tab = tab; ckh->tab = tab;
ckh->lg_curbuckets = lg_prevbuckets; ckh->lg_curbuckets = lg_prevbuckets;
} }
@@ -299,7 +300,7 @@ label_return:
} }
static void static void
ckh_shrink(tsdn_t *tsdn, ckh_t *ckh) ckh_shrink(tsd_t *tsd, ckh_t *ckh)
{ {
ckhc_t *tab, *ttab; ckhc_t *tab, *ttab;
size_t usize; size_t usize;
@@ -314,8 +315,8 @@ ckh_shrink(tsdn_t *tsdn, ckh_t *ckh)
usize = sa2u(sizeof(ckhc_t) << lg_curcells, CACHELINE); usize = sa2u(sizeof(ckhc_t) << lg_curcells, CACHELINE);
if (unlikely(usize == 0 || usize > HUGE_MAXCLASS)) if (unlikely(usize == 0 || usize > HUGE_MAXCLASS))
return; return;
tab = (ckhc_t *)ipallocztm(tsdn, usize, CACHELINE, true, NULL, true, tab = (ckhc_t *)ipallocztm(tsd_tsdn(tsd), usize, CACHELINE, true, NULL,
arena_ichoose(tsdn, NULL)); true, arena_ichoose(tsd, NULL));
if (tab == NULL) { if (tab == NULL) {
/* /*
* An OOM error isn't worth propagating, since it doesn't * An OOM error isn't worth propagating, since it doesn't
@@ -330,7 +331,7 @@ ckh_shrink(tsdn_t *tsdn, ckh_t *ckh)
ckh->lg_curbuckets = lg_curcells - LG_CKH_BUCKET_CELLS; ckh->lg_curbuckets = lg_curcells - LG_CKH_BUCKET_CELLS;
if (!ckh_rebuild(ckh, tab)) { if (!ckh_rebuild(ckh, tab)) {
idalloctm(tsdn, tab, NULL, true, true); idalloctm(tsd_tsdn(tsd), tab, NULL, true, true);
#ifdef CKH_COUNT #ifdef CKH_COUNT
ckh->nshrinks++; ckh->nshrinks++;
#endif #endif
@@ -338,7 +339,7 @@ ckh_shrink(tsdn_t *tsdn, ckh_t *ckh)
} }
/* Rebuilding failed, so back out partially rebuilt table. */ /* Rebuilding failed, so back out partially rebuilt table. */
idalloctm(tsdn, ckh->tab, NULL, true, true); idalloctm(tsd_tsdn(tsd), ckh->tab, NULL, true, true);
ckh->tab = tab; ckh->tab = tab;
ckh->lg_curbuckets = lg_prevbuckets; ckh->lg_curbuckets = lg_prevbuckets;
#ifdef CKH_COUNT #ifdef CKH_COUNT
@@ -347,7 +348,7 @@ ckh_shrink(tsdn_t *tsdn, ckh_t *ckh)
} }
bool bool
ckh_new(tsdn_t *tsdn, ckh_t *ckh, size_t minitems, ckh_hash_t *hash, ckh_new(tsd_t *tsd, ckh_t *ckh, size_t minitems, ckh_hash_t *hash,
ckh_keycomp_t *keycomp) ckh_keycomp_t *keycomp)
{ {
bool ret; bool ret;
@@ -391,8 +392,8 @@ ckh_new(tsdn_t *tsdn, ckh_t *ckh, size_t minitems, ckh_hash_t *hash,
ret = true; ret = true;
goto label_return; goto label_return;
} }
ckh->tab = (ckhc_t *)ipallocztm(tsdn, usize, CACHELINE, true, NULL, ckh->tab = (ckhc_t *)ipallocztm(tsd_tsdn(tsd), usize, CACHELINE, true,
true, arena_ichoose(tsdn, NULL)); NULL, true, arena_ichoose(tsd, NULL));
if (ckh->tab == NULL) { if (ckh->tab == NULL) {
ret = true; ret = true;
goto label_return; goto label_return;
@@ -404,7 +405,7 @@ label_return:
} }
void void
ckh_delete(tsdn_t *tsdn, ckh_t *ckh) ckh_delete(tsd_t *tsd, ckh_t *ckh)
{ {
assert(ckh != NULL); assert(ckh != NULL);
@@ -421,7 +422,7 @@ ckh_delete(tsdn_t *tsdn, ckh_t *ckh)
(unsigned long long)ckh->nrelocs); (unsigned long long)ckh->nrelocs);
#endif #endif
idalloctm(tsdn, ckh->tab, NULL, true, true); idalloctm(tsd_tsdn(tsd), ckh->tab, NULL, true, true);
if (config_debug) if (config_debug)
memset(ckh, JEMALLOC_FREE_JUNK, sizeof(ckh_t)); memset(ckh, JEMALLOC_FREE_JUNK, sizeof(ckh_t));
} }
@@ -456,7 +457,7 @@ ckh_iter(ckh_t *ckh, size_t *tabind, void **key, void **data)
} }
bool bool
ckh_insert(tsdn_t *tsdn, ckh_t *ckh, const void *key, const void *data) ckh_insert(tsd_t *tsd, ckh_t *ckh, const void *key, const void *data)
{ {
bool ret; bool ret;
@@ -468,7 +469,7 @@ ckh_insert(tsdn_t *tsdn, ckh_t *ckh, const void *key, const void *data)
#endif #endif
while (ckh_try_insert(ckh, &key, &data)) { while (ckh_try_insert(ckh, &key, &data)) {
if (ckh_grow(tsdn, ckh)) { if (ckh_grow(tsd, ckh)) {
ret = true; ret = true;
goto label_return; goto label_return;
} }
@@ -480,7 +481,7 @@ label_return:
} }
bool bool
ckh_remove(tsdn_t *tsdn, ckh_t *ckh, const void *searchkey, void **key, ckh_remove(tsd_t *tsd, ckh_t *ckh, const void *searchkey, void **key,
void **data) void **data)
{ {
size_t cell; size_t cell;
@@ -502,7 +503,7 @@ ckh_remove(tsdn_t *tsdn, ckh_t *ckh, const void *searchkey, void **key,
+ LG_CKH_BUCKET_CELLS - 2)) && ckh->lg_curbuckets + LG_CKH_BUCKET_CELLS - 2)) && ckh->lg_curbuckets
> ckh->lg_minbuckets) { > ckh->lg_minbuckets) {
/* Ignore error due to OOM. */ /* Ignore error due to OOM. */
ckh_shrink(tsdn, ckh); ckh_shrink(tsd, ckh);
} }
return (false); return (false);

View File

@@ -84,6 +84,7 @@ CTL_PROTO(config_prof_libgcc)
CTL_PROTO(config_prof_libunwind) CTL_PROTO(config_prof_libunwind)
CTL_PROTO(config_stats) CTL_PROTO(config_stats)
CTL_PROTO(config_tcache) CTL_PROTO(config_tcache)
CTL_PROTO(config_thp)
CTL_PROTO(config_tls) CTL_PROTO(config_tls)
CTL_PROTO(config_utrace) CTL_PROTO(config_utrace)
CTL_PROTO(config_valgrind) CTL_PROTO(config_valgrind)
@@ -104,6 +105,7 @@ CTL_PROTO(opt_utrace)
CTL_PROTO(opt_xmalloc) CTL_PROTO(opt_xmalloc)
CTL_PROTO(opt_tcache) CTL_PROTO(opt_tcache)
CTL_PROTO(opt_lg_tcache_max) CTL_PROTO(opt_lg_tcache_max)
CTL_PROTO(opt_thp)
CTL_PROTO(opt_prof) CTL_PROTO(opt_prof)
CTL_PROTO(opt_prof_prefix) CTL_PROTO(opt_prof_prefix)
CTL_PROTO(opt_prof_active) CTL_PROTO(opt_prof_active)
@@ -258,6 +260,7 @@ static const ctl_named_node_t config_node[] = {
{NAME("prof_libunwind"), CTL(config_prof_libunwind)}, {NAME("prof_libunwind"), CTL(config_prof_libunwind)},
{NAME("stats"), CTL(config_stats)}, {NAME("stats"), CTL(config_stats)},
{NAME("tcache"), CTL(config_tcache)}, {NAME("tcache"), CTL(config_tcache)},
{NAME("thp"), CTL(config_thp)},
{NAME("tls"), CTL(config_tls)}, {NAME("tls"), CTL(config_tls)},
{NAME("utrace"), CTL(config_utrace)}, {NAME("utrace"), CTL(config_utrace)},
{NAME("valgrind"), CTL(config_valgrind)}, {NAME("valgrind"), CTL(config_valgrind)},
@@ -281,6 +284,7 @@ static const ctl_named_node_t opt_node[] = {
{NAME("xmalloc"), CTL(opt_xmalloc)}, {NAME("xmalloc"), CTL(opt_xmalloc)},
{NAME("tcache"), CTL(opt_tcache)}, {NAME("tcache"), CTL(opt_tcache)},
{NAME("lg_tcache_max"), CTL(opt_lg_tcache_max)}, {NAME("lg_tcache_max"), CTL(opt_lg_tcache_max)},
{NAME("thp"), CTL(opt_thp)},
{NAME("prof"), CTL(opt_prof)}, {NAME("prof"), CTL(opt_prof)},
{NAME("prof_prefix"), CTL(opt_prof_prefix)}, {NAME("prof_prefix"), CTL(opt_prof_prefix)},
{NAME("prof_active"), CTL(opt_prof_active)}, {NAME("prof_active"), CTL(opt_prof_active)},
@@ -1268,6 +1272,7 @@ CTL_RO_CONFIG_GEN(config_prof_libgcc, bool)
CTL_RO_CONFIG_GEN(config_prof_libunwind, bool) CTL_RO_CONFIG_GEN(config_prof_libunwind, bool)
CTL_RO_CONFIG_GEN(config_stats, bool) CTL_RO_CONFIG_GEN(config_stats, bool)
CTL_RO_CONFIG_GEN(config_tcache, bool) CTL_RO_CONFIG_GEN(config_tcache, bool)
CTL_RO_CONFIG_GEN(config_thp, bool)
CTL_RO_CONFIG_GEN(config_tls, bool) CTL_RO_CONFIG_GEN(config_tls, bool)
CTL_RO_CONFIG_GEN(config_utrace, bool) CTL_RO_CONFIG_GEN(config_utrace, bool)
CTL_RO_CONFIG_GEN(config_valgrind, bool) CTL_RO_CONFIG_GEN(config_valgrind, bool)
@@ -1291,6 +1296,7 @@ CTL_RO_NL_CGEN(config_utrace, opt_utrace, opt_utrace, bool)
CTL_RO_NL_CGEN(config_xmalloc, opt_xmalloc, opt_xmalloc, bool) CTL_RO_NL_CGEN(config_xmalloc, opt_xmalloc, opt_xmalloc, bool)
CTL_RO_NL_CGEN(config_tcache, opt_tcache, opt_tcache, bool) CTL_RO_NL_CGEN(config_tcache, opt_tcache, opt_tcache, bool)
CTL_RO_NL_CGEN(config_tcache, opt_lg_tcache_max, opt_lg_tcache_max, ssize_t) CTL_RO_NL_CGEN(config_tcache, opt_lg_tcache_max, opt_lg_tcache_max, ssize_t)
CTL_RO_NL_CGEN(config_thp, opt_thp, opt_thp, bool)
CTL_RO_NL_CGEN(config_prof, opt_prof, opt_prof, bool) CTL_RO_NL_CGEN(config_prof, opt_prof, opt_prof, bool)
CTL_RO_NL_CGEN(config_prof, opt_prof_prefix, opt_prof_prefix, const char *) CTL_RO_NL_CGEN(config_prof, opt_prof_prefix, opt_prof_prefix, const char *)
CTL_RO_NL_CGEN(config_prof, opt_prof_active, opt_prof_active, bool) CTL_RO_NL_CGEN(config_prof, opt_prof_active, opt_prof_active, bool)
@@ -1476,9 +1482,8 @@ tcache_create_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp,
if (!config_tcache) if (!config_tcache)
return (ENOENT); return (ENOENT);
malloc_mutex_lock(tsd_tsdn(tsd), &ctl_mtx);
READONLY(); READONLY();
if (tcaches_create(tsd_tsdn(tsd), &tcache_ind)) { if (tcaches_create(tsd, &tcache_ind)) {
ret = EFAULT; ret = EFAULT;
goto label_return; goto label_return;
} }
@@ -1486,8 +1491,7 @@ tcache_create_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp,
ret = 0; ret = 0;
label_return: label_return:
malloc_mutex_unlock(tsd_tsdn(tsd), &ctl_mtx); return ret;
return (ret);
} }
static int static int
@@ -1685,11 +1689,11 @@ arena_i_dss_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp,
dss_prec_old = arena_dss_prec_get(tsd_tsdn(tsd), arena); dss_prec_old = arena_dss_prec_get(tsd_tsdn(tsd), arena);
} else { } else {
if (dss_prec != dss_prec_limit && if (dss_prec != dss_prec_limit &&
chunk_dss_prec_set(tsd_tsdn(tsd), dss_prec)) { chunk_dss_prec_set(dss_prec)) {
ret = EFAULT; ret = EFAULT;
goto label_return; goto label_return;
} }
dss_prec_old = chunk_dss_prec_get(tsd_tsdn(tsd)); dss_prec_old = chunk_dss_prec_get();
} }
dss = dss_prec_names[dss_prec_old]; dss = dss_prec_names[dss_prec_old];
@@ -2100,7 +2104,7 @@ prof_reset_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp,
if (lg_sample >= (sizeof(uint64_t) << 3)) if (lg_sample >= (sizeof(uint64_t) << 3))
lg_sample = (sizeof(uint64_t) << 3) - 1; lg_sample = (sizeof(uint64_t) << 3) - 1;
prof_reset(tsd_tsdn(tsd), lg_sample); prof_reset(tsd, lg_sample);
ret = 0; ret = 0;
label_return: label_return:

View File

@@ -3,42 +3,64 @@
/******************************************************************************/ /******************************************************************************/
JEMALLOC_INLINE_C size_t #ifndef JEMALLOC_JET
extent_quantize(size_t size) static
{ #endif
size_t
extent_size_quantize_floor(size_t size) {
size_t ret;
szind_t ind;
/* assert(size > 0);
* Round down to the nearest chunk size that can actually be requested
* during normal huge allocation.
*/
return (index2size(size2index(size + 1) - 1));
}
JEMALLOC_INLINE_C int ind = size2index(size + 1);
extent_szad_comp(const extent_node_t *a, const extent_node_t *b) if (ind == 0) {
{ /* Avoid underflow. */
int ret; return (index2size(0));
size_t a_qsize = extent_quantize(extent_node_size_get(a));
size_t b_qsize = extent_quantize(extent_node_size_get(b));
/*
* Compare based on quantized size rather than size, in order to sort
* equally useful extents only by address.
*/
ret = (a_qsize > b_qsize) - (a_qsize < b_qsize);
if (ret == 0) {
uintptr_t a_addr = (uintptr_t)extent_node_addr_get(a);
uintptr_t b_addr = (uintptr_t)extent_node_addr_get(b);
ret = (a_addr > b_addr) - (a_addr < b_addr);
} }
ret = index2size(ind - 1);
assert(ret <= size);
return (ret); return (ret);
} }
/* Generate red-black tree functions. */ size_t
rb_gen(, extent_tree_szad_, extent_tree_t, extent_node_t, szad_link, extent_size_quantize_ceil(size_t size) {
extent_szad_comp) size_t ret;
assert(size > 0);
ret = extent_size_quantize_floor(size);
if (ret < size) {
/*
* Skip a quantization that may have an adequately large extent,
* because under-sized extents may be mixed in. This only
* happens when an unusual size is requested, i.e. for aligned
* allocation, and is just one of several places where linear
* search would potentially find sufficiently aligned available
* memory somewhere lower.
*/
ret = index2size(size2index(ret + 1));
}
return ret;
}
JEMALLOC_INLINE_C int
extent_sz_comp(const extent_node_t *a, const extent_node_t *b)
{
size_t a_qsize = extent_size_quantize_floor(extent_node_size_get(a));
size_t b_qsize = extent_size_quantize_floor(extent_node_size_get(b));
return ((a_qsize > b_qsize) - (a_qsize < b_qsize));
}
JEMALLOC_INLINE_C int
extent_sn_comp(const extent_node_t *a, const extent_node_t *b)
{
size_t a_sn = extent_node_sn_get(a);
size_t b_sn = extent_node_sn_get(b);
return ((a_sn > b_sn) - (a_sn < b_sn));
}
JEMALLOC_INLINE_C int JEMALLOC_INLINE_C int
extent_ad_comp(const extent_node_t *a, const extent_node_t *b) extent_ad_comp(const extent_node_t *a, const extent_node_t *b)
@@ -49,5 +71,26 @@ extent_ad_comp(const extent_node_t *a, const extent_node_t *b)
return ((a_addr > b_addr) - (a_addr < b_addr)); return ((a_addr > b_addr) - (a_addr < b_addr));
} }
JEMALLOC_INLINE_C int
extent_szsnad_comp(const extent_node_t *a, const extent_node_t *b)
{
int ret;
ret = extent_sz_comp(a, b);
if (ret != 0)
return (ret);
ret = extent_sn_comp(a, b);
if (ret != 0)
return (ret);
ret = extent_ad_comp(a, b);
return (ret);
}
/* Generate red-black tree functions. */
rb_gen(, extent_tree_szsnad_, extent_tree_t, extent_node_t, szsnad_link,
extent_szsnad_comp)
/* Generate red-black tree functions. */ /* Generate red-black tree functions. */
rb_gen(, extent_tree_ad_, extent_tree_t, extent_node_t, ad_link, extent_ad_comp) rb_gen(, extent_tree_ad_, extent_tree_t, extent_node_t, ad_link, extent_ad_comp)

View File

@@ -15,20 +15,20 @@ huge_node_get(const void *ptr)
} }
static bool static bool
huge_node_set(tsdn_t *tsdn, const void *ptr, extent_node_t *node) huge_node_set(tsdn_t *tsdn, const void *ptr, extent_node_t *node, bool *gdump)
{ {
assert(extent_node_addr_get(node) == ptr); assert(extent_node_addr_get(node) == ptr);
assert(!extent_node_achunk_get(node)); assert(!extent_node_achunk_get(node));
return (chunk_register(tsdn, ptr, node)); return (chunk_register(ptr, node, gdump));
} }
static void static void
huge_node_reset(tsdn_t *tsdn, const void *ptr, extent_node_t *node) huge_node_reset(tsdn_t *tsdn, const void *ptr, extent_node_t *node, bool *gdump)
{ {
bool err; bool err;
err = huge_node_set(tsdn, ptr, node); err = huge_node_set(tsdn, ptr, node, gdump);
assert(!err); assert(!err);
} }
@@ -54,12 +54,16 @@ huge_palloc(tsdn_t *tsdn, arena_t *arena, size_t usize, size_t alignment,
{ {
void *ret; void *ret;
size_t ausize; size_t ausize;
arena_t *iarena;
extent_node_t *node; extent_node_t *node;
bool is_zeroed; size_t sn;
bool is_zeroed, gdump;
/* Allocate one or more contiguous chunks for this request. */ /* Allocate one or more contiguous chunks for this request. */
assert(!tsdn_null(tsdn) || arena != NULL); assert(!tsdn_null(tsdn) || arena != NULL);
/* prof_gdump() requirement. */
witness_assert_depth_to_rank(tsdn, WITNESS_RANK_CORE, 0);
ausize = sa2u(usize, alignment); ausize = sa2u(usize, alignment);
if (unlikely(ausize == 0 || ausize > HUGE_MAXCLASS)) if (unlikely(ausize == 0 || ausize > HUGE_MAXCLASS))
@@ -67,8 +71,10 @@ huge_palloc(tsdn_t *tsdn, arena_t *arena, size_t usize, size_t alignment,
assert(ausize >= chunksize); assert(ausize >= chunksize);
/* Allocate an extent node with which to track the chunk. */ /* Allocate an extent node with which to track the chunk. */
iarena = (!tsdn_null(tsdn)) ? arena_ichoose(tsdn_tsd(tsdn), NULL) :
a0get();
node = ipallocztm(tsdn, CACHELINE_CEILING(sizeof(extent_node_t)), node = ipallocztm(tsdn, CACHELINE_CEILING(sizeof(extent_node_t)),
CACHELINE, false, NULL, true, arena_ichoose(tsdn, arena)); CACHELINE, false, NULL, true, iarena);
if (node == NULL) if (node == NULL)
return (NULL); return (NULL);
@@ -80,18 +86,20 @@ huge_palloc(tsdn_t *tsdn, arena_t *arena, size_t usize, size_t alignment,
if (likely(!tsdn_null(tsdn))) if (likely(!tsdn_null(tsdn)))
arena = arena_choose(tsdn_tsd(tsdn), arena); arena = arena_choose(tsdn_tsd(tsdn), arena);
if (unlikely(arena == NULL) || (ret = arena_chunk_alloc_huge(tsdn, if (unlikely(arena == NULL) || (ret = arena_chunk_alloc_huge(tsdn,
arena, usize, alignment, &is_zeroed)) == NULL) { arena, usize, alignment, &sn, &is_zeroed)) == NULL) {
idalloctm(tsdn, node, NULL, true, true); idalloctm(tsdn, node, NULL, true, true);
return (NULL); return (NULL);
} }
extent_node_init(node, arena, ret, usize, is_zeroed, true); extent_node_init(node, arena, ret, usize, sn, is_zeroed, true);
if (huge_node_set(tsdn, ret, node)) { if (huge_node_set(tsdn, ret, node, &gdump)) {
arena_chunk_dalloc_huge(tsdn, arena, ret, usize); arena_chunk_dalloc_huge(tsdn, arena, ret, usize, sn);
idalloctm(tsdn, node, NULL, true, true); idalloctm(tsdn, node, NULL, true, true);
return (NULL); return (NULL);
} }
if (config_prof && opt_prof && gdump)
prof_gdump(tsdn);
/* Insert node into huge. */ /* Insert node into huge. */
malloc_mutex_lock(tsdn, &arena->huge_mtx); malloc_mutex_lock(tsdn, &arena->huge_mtx);
@@ -114,7 +122,7 @@ huge_palloc(tsdn_t *tsdn, arena_t *arena, size_t usize, size_t alignment,
#define huge_dalloc_junk JEMALLOC_N(huge_dalloc_junk_impl) #define huge_dalloc_junk JEMALLOC_N(huge_dalloc_junk_impl)
#endif #endif
static void static void
huge_dalloc_junk(tsdn_t *tsdn, void *ptr, size_t usize) huge_dalloc_junk(void *ptr, size_t usize)
{ {
if (config_fill && have_dss && unlikely(opt_junk_free)) { if (config_fill && have_dss && unlikely(opt_junk_free)) {
@@ -122,7 +130,7 @@ huge_dalloc_junk(tsdn_t *tsdn, void *ptr, size_t usize)
* Only bother junk filling if the chunk isn't about to be * Only bother junk filling if the chunk isn't about to be
* unmapped. * unmapped.
*/ */
if (!config_munmap || (have_dss && chunk_in_dss(tsdn, ptr))) if (!config_munmap || (have_dss && chunk_in_dss(ptr)))
memset(ptr, JEMALLOC_FREE_JUNK, usize); memset(ptr, JEMALLOC_FREE_JUNK, usize);
} }
} }
@@ -140,7 +148,10 @@ huge_ralloc_no_move_similar(tsdn_t *tsdn, void *ptr, size_t oldsize,
extent_node_t *node; extent_node_t *node;
arena_t *arena; arena_t *arena;
chunk_hooks_t chunk_hooks = CHUNK_HOOKS_INITIALIZER; chunk_hooks_t chunk_hooks = CHUNK_HOOKS_INITIALIZER;
bool pre_zeroed, post_zeroed; bool pre_zeroed, post_zeroed, gdump;
/* prof_gdump() requirement. */
witness_assert_depth_to_rank(tsdn, WITNESS_RANK_CORE, 0);
/* Increase usize to incorporate extra. */ /* Increase usize to incorporate extra. */
for (usize = usize_min; usize < usize_max && (usize_next = s2u(usize+1)) for (usize = usize_min; usize < usize_max && (usize_next = s2u(usize+1))
@@ -174,10 +185,13 @@ huge_ralloc_no_move_similar(tsdn_t *tsdn, void *ptr, size_t oldsize,
huge_node_unset(ptr, node); huge_node_unset(ptr, node);
assert(extent_node_size_get(node) != usize); assert(extent_node_size_get(node) != usize);
extent_node_size_set(node, usize); extent_node_size_set(node, usize);
huge_node_reset(tsdn, ptr, node); huge_node_reset(tsdn, ptr, node, &gdump);
/* Update zeroed. */ /* Update zeroed. */
extent_node_zeroed_set(node, post_zeroed); extent_node_zeroed_set(node, post_zeroed);
malloc_mutex_unlock(tsdn, &arena->huge_mtx); malloc_mutex_unlock(tsdn, &arena->huge_mtx);
/* gdump without any locks held. */
if (config_prof && opt_prof && gdump)
prof_gdump(tsdn);
arena_chunk_ralloc_huge_similar(tsdn, arena, ptr, oldsize, usize); arena_chunk_ralloc_huge_similar(tsdn, arena, ptr, oldsize, usize);
@@ -203,7 +217,7 @@ huge_ralloc_no_move_shrink(tsdn_t *tsdn, void *ptr, size_t oldsize,
arena_t *arena; arena_t *arena;
chunk_hooks_t chunk_hooks; chunk_hooks_t chunk_hooks;
size_t cdiff; size_t cdiff;
bool pre_zeroed, post_zeroed; bool pre_zeroed, post_zeroed, gdump;
node = huge_node_get(ptr); node = huge_node_get(ptr);
arena = extent_node_arena_get(node); arena = extent_node_arena_get(node);
@@ -211,6 +225,8 @@ huge_ralloc_no_move_shrink(tsdn_t *tsdn, void *ptr, size_t oldsize,
chunk_hooks = chunk_hooks_get(tsdn, arena); chunk_hooks = chunk_hooks_get(tsdn, arena);
assert(oldsize > usize); assert(oldsize > usize);
/* prof_gdump() requirement. */
witness_assert_depth_to_rank(tsdn, WITNESS_RANK_CORE, 0);
/* Split excess chunks. */ /* Split excess chunks. */
cdiff = CHUNK_CEILING(oldsize) - CHUNK_CEILING(usize); cdiff = CHUNK_CEILING(oldsize) - CHUNK_CEILING(usize);
@@ -221,7 +237,7 @@ huge_ralloc_no_move_shrink(tsdn_t *tsdn, void *ptr, size_t oldsize,
if (oldsize > usize) { if (oldsize > usize) {
size_t sdiff = oldsize - usize; size_t sdiff = oldsize - usize;
if (config_fill && unlikely(opt_junk_free)) { if (config_fill && unlikely(opt_junk_free)) {
huge_dalloc_junk(tsdn, (void *)((uintptr_t)ptr + usize), huge_dalloc_junk((void *)((uintptr_t)ptr + usize),
sdiff); sdiff);
post_zeroed = false; post_zeroed = false;
} else { } else {
@@ -237,13 +253,17 @@ huge_ralloc_no_move_shrink(tsdn_t *tsdn, void *ptr, size_t oldsize,
/* Update the size of the huge allocation. */ /* Update the size of the huge allocation. */
huge_node_unset(ptr, node); huge_node_unset(ptr, node);
extent_node_size_set(node, usize); extent_node_size_set(node, usize);
huge_node_reset(tsdn, ptr, node); huge_node_reset(tsdn, ptr, node, &gdump);
/* Update zeroed. */ /* Update zeroed. */
extent_node_zeroed_set(node, post_zeroed); extent_node_zeroed_set(node, post_zeroed);
malloc_mutex_unlock(tsdn, &arena->huge_mtx); malloc_mutex_unlock(tsdn, &arena->huge_mtx);
/* gdump without any locks held. */
if (config_prof && opt_prof && gdump)
prof_gdump(tsdn);
/* Zap the excess chunks. */ /* Zap the excess chunks. */
arena_chunk_ralloc_huge_shrink(tsdn, arena, ptr, oldsize, usize); arena_chunk_ralloc_huge_shrink(tsdn, arena, ptr, oldsize, usize,
extent_node_sn_get(node));
return (false); return (false);
} }
@@ -253,7 +273,7 @@ huge_ralloc_no_move_expand(tsdn_t *tsdn, void *ptr, size_t oldsize,
size_t usize, bool zero) { size_t usize, bool zero) {
extent_node_t *node; extent_node_t *node;
arena_t *arena; arena_t *arena;
bool is_zeroed_subchunk, is_zeroed_chunk; bool is_zeroed_subchunk, is_zeroed_chunk, gdump;
node = huge_node_get(ptr); node = huge_node_get(ptr);
arena = extent_node_arena_get(node); arena = extent_node_arena_get(node);
@@ -261,22 +281,28 @@ huge_ralloc_no_move_expand(tsdn_t *tsdn, void *ptr, size_t oldsize,
is_zeroed_subchunk = extent_node_zeroed_get(node); is_zeroed_subchunk = extent_node_zeroed_get(node);
malloc_mutex_unlock(tsdn, &arena->huge_mtx); malloc_mutex_unlock(tsdn, &arena->huge_mtx);
/* /* prof_gdump() requirement. */
* Copy zero into is_zeroed_chunk and pass the copy to chunk_alloc(), so witness_assert_depth_to_rank(tsdn, WITNESS_RANK_CORE, 0);
* that it is possible to make correct junk/zero fill decisions below.
*/
is_zeroed_chunk = zero;
/*
* Use is_zeroed_chunk to detect whether the trailing memory is zeroed,
* update extent's zeroed field, and zero as necessary.
*/
is_zeroed_chunk = false;
if (arena_chunk_ralloc_huge_expand(tsdn, arena, ptr, oldsize, usize, if (arena_chunk_ralloc_huge_expand(tsdn, arena, ptr, oldsize, usize,
&is_zeroed_chunk)) &is_zeroed_chunk))
return (true); return (true);
malloc_mutex_lock(tsdn, &arena->huge_mtx); malloc_mutex_lock(tsdn, &arena->huge_mtx);
/* Update the size of the huge allocation. */
huge_node_unset(ptr, node); huge_node_unset(ptr, node);
extent_node_size_set(node, usize); extent_node_size_set(node, usize);
huge_node_reset(tsdn, ptr, node); extent_node_zeroed_set(node, extent_node_zeroed_get(node) &&
is_zeroed_chunk);
huge_node_reset(tsdn, ptr, node, &gdump);
malloc_mutex_unlock(tsdn, &arena->huge_mtx); malloc_mutex_unlock(tsdn, &arena->huge_mtx);
/* gdump without any locks held. */
if (config_prof && opt_prof && gdump)
prof_gdump(tsdn);
if (zero || (config_fill && unlikely(opt_zero))) { if (zero || (config_fill && unlikely(opt_zero))) {
if (!is_zeroed_subchunk) { if (!is_zeroed_subchunk) {
@@ -402,10 +428,11 @@ huge_dalloc(tsdn_t *tsdn, void *ptr)
ql_remove(&arena->huge, node, ql_link); ql_remove(&arena->huge, node, ql_link);
malloc_mutex_unlock(tsdn, &arena->huge_mtx); malloc_mutex_unlock(tsdn, &arena->huge_mtx);
huge_dalloc_junk(tsdn, extent_node_addr_get(node), huge_dalloc_junk(extent_node_addr_get(node),
extent_node_size_get(node)); extent_node_size_get(node));
arena_chunk_dalloc_huge(tsdn, extent_node_arena_get(node), arena_chunk_dalloc_huge(tsdn, extent_node_arena_get(node),
extent_node_addr_get(node), extent_node_size_get(node)); extent_node_addr_get(node), extent_node_size_get(node),
extent_node_sn_get(node));
idalloctm(tsdn, node, NULL, true, true); idalloctm(tsdn, node, NULL, true, true);
arena_decay_tick(tsdn, arena); arena_decay_tick(tsdn, arena);

View File

@@ -5,7 +5,11 @@
/* Data. */ /* Data. */
/* Runtime configuration options. */ /* Runtime configuration options. */
const char *je_malloc_conf JEMALLOC_ATTR(weak); const char *je_malloc_conf
#ifndef _WIN32
JEMALLOC_ATTR(weak)
#endif
;
bool opt_abort = bool opt_abort =
#ifdef JEMALLOC_DEBUG #ifdef JEMALLOC_DEBUG
true true
@@ -85,14 +89,25 @@ enum {
}; };
static uint8_t malloc_slow_flags; static uint8_t malloc_slow_flags;
/* Last entry for overflow detection only. */
JEMALLOC_ALIGNED(CACHELINE) JEMALLOC_ALIGNED(CACHELINE)
const size_t index2size_tab[NSIZES+1] = { const size_t pind2sz_tab[NPSIZES] = {
#define SC(index, lg_grp, lg_delta, ndelta, bin, lg_delta_lookup) \ #define PSZ_yes(lg_grp, ndelta, lg_delta) \
(((ZU(1)<<lg_grp) + (ZU(ndelta)<<lg_delta))),
#define PSZ_no(lg_grp, ndelta, lg_delta)
#define SC(index, lg_grp, lg_delta, ndelta, psz, bin, lg_delta_lookup) \
PSZ_##psz(lg_grp, ndelta, lg_delta)
SIZE_CLASSES
#undef PSZ_yes
#undef PSZ_no
#undef SC
};
JEMALLOC_ALIGNED(CACHELINE)
const size_t index2size_tab[NSIZES] = {
#define SC(index, lg_grp, lg_delta, ndelta, psz, bin, lg_delta_lookup) \
((ZU(1)<<lg_grp) + (ZU(ndelta)<<lg_delta)), ((ZU(1)<<lg_grp) + (ZU(ndelta)<<lg_delta)),
SIZE_CLASSES SIZE_CLASSES
#undef SC #undef SC
ZU(0)
}; };
JEMALLOC_ALIGNED(CACHELINE) JEMALLOC_ALIGNED(CACHELINE)
@@ -161,7 +176,7 @@ const uint8_t size2index_tab[] = {
#define S2B_11(i) S2B_10(i) S2B_10(i) #define S2B_11(i) S2B_10(i) S2B_10(i)
#endif #endif
#define S2B_no(i) #define S2B_no(i)
#define SC(index, lg_grp, lg_delta, ndelta, bin, lg_delta_lookup) \ #define SC(index, lg_grp, lg_delta, ndelta, psz, bin, lg_delta_lookup) \
S2B_##lg_delta_lookup(index) S2B_##lg_delta_lookup(index)
SIZE_CLASSES SIZE_CLASSES
#undef S2B_3 #undef S2B_3
@@ -329,6 +344,13 @@ a0idalloc(void *ptr, bool is_metadata)
idalloctm(TSDN_NULL, ptr, false, is_metadata, true); idalloctm(TSDN_NULL, ptr, false, is_metadata, true);
} }
arena_t *
a0get(void)
{
return (a0);
}
void * void *
a0malloc(size_t size) a0malloc(size_t size)
{ {
@@ -455,15 +477,16 @@ arena_bind(tsd_t *tsd, unsigned ind, bool internal)
{ {
arena_t *arena; arena_t *arena;
if (!tsd_nominal(tsd))
return;
arena = arena_get(tsd_tsdn(tsd), ind, false); arena = arena_get(tsd_tsdn(tsd), ind, false);
arena_nthreads_inc(arena, internal); arena_nthreads_inc(arena, internal);
if (tsd_nominal(tsd)) { if (internal)
if (internal) tsd_iarena_set(tsd, arena);
tsd_iarena_set(tsd, arena); else
else tsd_arena_set(tsd, arena);
tsd_arena_set(tsd, arena);
}
} }
void void
@@ -767,18 +790,19 @@ stats_print_atexit(void)
* Begin initialization functions. * Begin initialization functions.
*/ */
#ifndef JEMALLOC_HAVE_SECURE_GETENV
static char * static char *
secure_getenv(const char *name) jemalloc_secure_getenv(const char *name)
{ {
#ifdef JEMALLOC_HAVE_SECURE_GETENV
return secure_getenv(name);
#else
# ifdef JEMALLOC_HAVE_ISSETUGID # ifdef JEMALLOC_HAVE_ISSETUGID
if (issetugid() != 0) if (issetugid() != 0)
return (NULL); return (NULL);
# endif # endif
return (getenv(name)); return (getenv(name));
}
#endif #endif
}
static unsigned static unsigned
malloc_ncpus(void) malloc_ncpus(void)
@@ -789,6 +813,20 @@ malloc_ncpus(void)
SYSTEM_INFO si; SYSTEM_INFO si;
GetSystemInfo(&si); GetSystemInfo(&si);
result = si.dwNumberOfProcessors; result = si.dwNumberOfProcessors;
#elif defined(JEMALLOC_GLIBC_MALLOC_HOOK) && defined(CPU_COUNT)
/*
* glibc >= 2.6 has the CPU_COUNT macro.
*
* glibc's sysconf() uses isspace(). glibc allocates for the first time
* *before* setting up the isspace tables. Therefore we need a
* different method to get the number of CPUs.
*/
{
cpu_set_t set;
pthread_getaffinity_np(pthread_self(), sizeof(set), &set);
result = CPU_COUNT(&set);
}
#else #else
result = sysconf(_SC_NPROCESSORS_ONLN); result = sysconf(_SC_NPROCESSORS_ONLN);
#endif #endif
@@ -981,7 +1019,7 @@ malloc_conf_init(void)
#endif #endif
; ;
if ((opts = secure_getenv(envname)) != NULL) { if ((opts = jemalloc_secure_getenv(envname)) != NULL) {
/* /*
* Do nothing; opts is already initialized to * Do nothing; opts is already initialized to
* the value of the MALLOC_CONF environment * the value of the MALLOC_CONF environment
@@ -1019,7 +1057,11 @@ malloc_conf_init(void)
if (cont) \ if (cont) \
continue; \ continue; \
} }
#define CONF_HANDLE_T_U(t, o, n, min, max, clip) \ #define CONF_MIN_no(um, min) false
#define CONF_MIN_yes(um, min) ((um) < (min))
#define CONF_MAX_no(um, max) false
#define CONF_MAX_yes(um, max) ((um) > (max))
#define CONF_HANDLE_T_U(t, o, n, min, max, check_min, check_max, clip) \
if (CONF_MATCH(n)) { \ if (CONF_MATCH(n)) { \
uintmax_t um; \ uintmax_t um; \
char *end; \ char *end; \
@@ -1032,15 +1074,19 @@ malloc_conf_init(void)
"Invalid conf value", \ "Invalid conf value", \
k, klen, v, vlen); \ k, klen, v, vlen); \
} else if (clip) { \ } else if (clip) { \
if ((min) != 0 && um < (min)) \ if (CONF_MIN_##check_min(um, \
(t)(min))) \
o = (t)(min); \ o = (t)(min); \
else if (um > (max)) \ else if (CONF_MAX_##check_max( \
um, (t)(max))) \
o = (t)(max); \ o = (t)(max); \
else \ else \
o = (t)um; \ o = (t)um; \
} else { \ } else { \
if (((min) != 0 && um < (min)) \ if (CONF_MIN_##check_min(um, \
|| um > (max)) { \ (t)(min)) || \
CONF_MAX_##check_max(um, \
(t)(max))) { \
malloc_conf_error( \ malloc_conf_error( \
"Out-of-range " \ "Out-of-range " \
"conf value", \ "conf value", \
@@ -1050,10 +1096,13 @@ malloc_conf_init(void)
} \ } \
continue; \ continue; \
} }
#define CONF_HANDLE_UNSIGNED(o, n, min, max, clip) \ #define CONF_HANDLE_UNSIGNED(o, n, min, max, check_min, check_max, \
CONF_HANDLE_T_U(unsigned, o, n, min, max, clip) clip) \
#define CONF_HANDLE_SIZE_T(o, n, min, max, clip) \ CONF_HANDLE_T_U(unsigned, o, n, min, max, \
CONF_HANDLE_T_U(size_t, o, n, min, max, clip) check_min, check_max, clip)
#define CONF_HANDLE_SIZE_T(o, n, min, max, check_min, check_max, clip) \
CONF_HANDLE_T_U(size_t, o, n, min, max, \
check_min, check_max, clip)
#define CONF_HANDLE_SSIZE_T(o, n, min, max) \ #define CONF_HANDLE_SSIZE_T(o, n, min, max) \
if (CONF_MATCH(n)) { \ if (CONF_MATCH(n)) { \
long l; \ long l; \
@@ -1087,24 +1136,25 @@ malloc_conf_init(void)
CONF_HANDLE_BOOL(opt_abort, "abort", true) CONF_HANDLE_BOOL(opt_abort, "abort", true)
/* /*
* Chunks always require at least one header page, * Chunks always require at least one header page, as
* as many as 2^(LG_SIZE_CLASS_GROUP+1) data pages, and * many as 2^(LG_SIZE_CLASS_GROUP+1) data pages (plus an
* possibly an additional page in the presence of * additional page in the presence of cache-oblivious
* redzones. In order to simplify options processing, * large), and possibly an additional page in the
* use a conservative bound that accommodates all these * presence of redzones. In order to simplify options
* constraints. * processing, use a conservative bound that
* accommodates all these constraints.
*/ */
CONF_HANDLE_SIZE_T(opt_lg_chunk, "lg_chunk", LG_PAGE + CONF_HANDLE_SIZE_T(opt_lg_chunk, "lg_chunk", LG_PAGE +
LG_SIZE_CLASS_GROUP + (config_fill ? 2 : 1), LG_SIZE_CLASS_GROUP + 1 + ((config_cache_oblivious
(sizeof(size_t) << 3) - 1, true) || config_fill) ? 1 : 0), (sizeof(size_t) << 3) - 1,
yes, yes, true)
if (strncmp("dss", k, klen) == 0) { if (strncmp("dss", k, klen) == 0) {
int i; int i;
bool match = false; bool match = false;
for (i = 0; i < dss_prec_limit; i++) { for (i = 0; i < dss_prec_limit; i++) {
if (strncmp(dss_prec_names[i], v, vlen) if (strncmp(dss_prec_names[i], v, vlen)
== 0) { == 0) {
if (chunk_dss_prec_set(NULL, if (chunk_dss_prec_set(i)) {
i)) {
malloc_conf_error( malloc_conf_error(
"Error setting dss", "Error setting dss",
k, klen, v, vlen); k, klen, v, vlen);
@@ -1123,7 +1173,7 @@ malloc_conf_init(void)
continue; continue;
} }
CONF_HANDLE_UNSIGNED(opt_narenas, "narenas", 1, CONF_HANDLE_UNSIGNED(opt_narenas, "narenas", 1,
UINT_MAX, false) UINT_MAX, yes, no, false)
if (strncmp("purge", k, klen) == 0) { if (strncmp("purge", k, klen) == 0) {
int i; int i;
bool match = false; bool match = false;
@@ -1149,9 +1199,20 @@ malloc_conf_init(void)
if (config_fill) { if (config_fill) {
if (CONF_MATCH("junk")) { if (CONF_MATCH("junk")) {
if (CONF_MATCH_VALUE("true")) { if (CONF_MATCH_VALUE("true")) {
opt_junk = "true"; if (config_valgrind &&
opt_junk_alloc = opt_junk_free = unlikely(in_valgrind)) {
true; malloc_conf_error(
"Deallocation-time "
"junk filling cannot "
"be enabled while "
"running inside "
"Valgrind", k, klen, v,
vlen);
} else {
opt_junk = "true";
opt_junk_alloc = true;
opt_junk_free = true;
}
} else if (CONF_MATCH_VALUE("false")) { } else if (CONF_MATCH_VALUE("false")) {
opt_junk = "false"; opt_junk = "false";
opt_junk_alloc = opt_junk_free = opt_junk_alloc = opt_junk_free =
@@ -1161,9 +1222,20 @@ malloc_conf_init(void)
opt_junk_alloc = true; opt_junk_alloc = true;
opt_junk_free = false; opt_junk_free = false;
} else if (CONF_MATCH_VALUE("free")) { } else if (CONF_MATCH_VALUE("free")) {
opt_junk = "free"; if (config_valgrind &&
opt_junk_alloc = false; unlikely(in_valgrind)) {
opt_junk_free = true; malloc_conf_error(
"Deallocation-time "
"junk filling cannot "
"be enabled while "
"running inside "
"Valgrind", k, klen, v,
vlen);
} else {
opt_junk = "free";
opt_junk_alloc = false;
opt_junk_free = true;
}
} else { } else {
malloc_conf_error( malloc_conf_error(
"Invalid conf value", k, "Invalid conf value", k,
@@ -1172,7 +1244,7 @@ malloc_conf_init(void)
continue; continue;
} }
CONF_HANDLE_SIZE_T(opt_quarantine, "quarantine", CONF_HANDLE_SIZE_T(opt_quarantine, "quarantine",
0, SIZE_T_MAX, false) 0, SIZE_T_MAX, no, no, false)
CONF_HANDLE_BOOL(opt_redzone, "redzone", true) CONF_HANDLE_BOOL(opt_redzone, "redzone", true)
CONF_HANDLE_BOOL(opt_zero, "zero", true) CONF_HANDLE_BOOL(opt_zero, "zero", true)
} }
@@ -1200,6 +1272,9 @@ malloc_conf_init(void)
"lg_tcache_max", -1, "lg_tcache_max", -1,
(sizeof(size_t) << 3) - 1) (sizeof(size_t) << 3) - 1)
} }
if (config_thp) {
CONF_HANDLE_BOOL(opt_thp, "thp", true)
}
if (config_prof) { if (config_prof) {
CONF_HANDLE_BOOL(opt_prof, "prof", true) CONF_HANDLE_BOOL(opt_prof, "prof", true)
CONF_HANDLE_CHAR_P(opt_prof_prefix, CONF_HANDLE_CHAR_P(opt_prof_prefix,
@@ -1209,8 +1284,8 @@ malloc_conf_init(void)
CONF_HANDLE_BOOL(opt_prof_thread_active_init, CONF_HANDLE_BOOL(opt_prof_thread_active_init,
"prof_thread_active_init", true) "prof_thread_active_init", true)
CONF_HANDLE_SIZE_T(opt_lg_prof_sample, CONF_HANDLE_SIZE_T(opt_lg_prof_sample,
"lg_prof_sample", 0, "lg_prof_sample", 0, (sizeof(uint64_t) << 3)
(sizeof(uint64_t) << 3) - 1, true) - 1, no, yes, true)
CONF_HANDLE_BOOL(opt_prof_accum, "prof_accum", CONF_HANDLE_BOOL(opt_prof_accum, "prof_accum",
true) true)
CONF_HANDLE_SSIZE_T(opt_lg_prof_interval, CONF_HANDLE_SSIZE_T(opt_lg_prof_interval,
@@ -1226,7 +1301,14 @@ malloc_conf_init(void)
malloc_conf_error("Invalid conf pair", k, klen, v, malloc_conf_error("Invalid conf pair", k, klen, v,
vlen); vlen);
#undef CONF_MATCH #undef CONF_MATCH
#undef CONF_MATCH_VALUE
#undef CONF_HANDLE_BOOL #undef CONF_HANDLE_BOOL
#undef CONF_MIN_no
#undef CONF_MIN_yes
#undef CONF_MAX_no
#undef CONF_MAX_yes
#undef CONF_HANDLE_T_U
#undef CONF_HANDLE_UNSIGNED
#undef CONF_HANDLE_SIZE_T #undef CONF_HANDLE_SIZE_T
#undef CONF_HANDLE_SSIZE_T #undef CONF_HANDLE_SSIZE_T
#undef CONF_HANDLE_CHAR_P #undef CONF_HANDLE_CHAR_P
@@ -1249,11 +1331,14 @@ malloc_init_hard_needed(void)
} }
#ifdef JEMALLOC_THREADED_INIT #ifdef JEMALLOC_THREADED_INIT
if (malloc_initializer != NO_INITIALIZER && !IS_INITIALIZER) { if (malloc_initializer != NO_INITIALIZER && !IS_INITIALIZER) {
spin_t spinner;
/* Busy-wait until the initializing thread completes. */ /* Busy-wait until the initializing thread completes. */
spin_init(&spinner);
do { do {
malloc_mutex_unlock(NULL, &init_lock); malloc_mutex_unlock(TSDN_NULL, &init_lock);
CPU_SPINWAIT; spin_adaptive(&spinner);
malloc_mutex_lock(NULL, &init_lock); malloc_mutex_lock(TSDN_NULL, &init_lock);
} while (!malloc_initialized()); } while (!malloc_initialized());
return (false); return (false);
} }
@@ -1287,8 +1372,7 @@ malloc_init_hard_a0_locked()
return (true); return (true);
if (config_prof) if (config_prof)
prof_boot1(); prof_boot1();
if (arena_boot()) arena_boot();
return (true);
if (config_tcache && tcache_boot(TSDN_NULL)) if (config_tcache && tcache_boot(TSDN_NULL))
return (true); return (true);
if (malloc_mutex_init(&arenas_lock, "arenas", WITNESS_RANK_ARENAS)) if (malloc_mutex_init(&arenas_lock, "arenas", WITNESS_RANK_ARENAS))
@@ -1333,8 +1417,9 @@ malloc_init_hard_recursible(void)
ncpus = malloc_ncpus(); ncpus = malloc_ncpus();
#if (!defined(JEMALLOC_MUTEX_INIT_CB) && !defined(JEMALLOC_ZONE) \ #if (defined(JEMALLOC_HAVE_PTHREAD_ATFORK) && !defined(JEMALLOC_MUTEX_INIT_CB) \
&& !defined(_WIN32) && !defined(__native_client__)) && !defined(JEMALLOC_ZONE) && !defined(_WIN32) && \
!defined(__native_client__))
/* LinuxThreads' pthread_atfork() allocates. */ /* LinuxThreads' pthread_atfork() allocates. */
if (pthread_atfork(jemalloc_prefork, jemalloc_postfork_parent, if (pthread_atfork(jemalloc_prefork, jemalloc_postfork_parent,
jemalloc_postfork_child) != 0) { jemalloc_postfork_child) != 0) {
@@ -1419,7 +1504,7 @@ malloc_init_hard(void)
return (true); return (true);
malloc_mutex_lock(tsd_tsdn(tsd), &init_lock); malloc_mutex_lock(tsd_tsdn(tsd), &init_lock);
if (config_prof && prof_boot2(tsd_tsdn(tsd))) { if (config_prof && prof_boot2(tsd)) {
malloc_mutex_unlock(tsd_tsdn(tsd), &init_lock); malloc_mutex_unlock(tsd_tsdn(tsd), &init_lock);
return (true); return (true);
} }
@@ -1739,7 +1824,7 @@ je_calloc(size_t num, size_t size)
ret = ialloc_body(num_size, true, &tsdn, &usize, true); ret = ialloc_body(num_size, true, &tsdn, &usize, true);
ialloc_post_check(ret, tsdn, usize, "calloc", true, true); ialloc_post_check(ret, tsdn, usize, "calloc", true, true);
UTRACE(0, num_size, ret); UTRACE(0, num_size, ret);
JEMALLOC_VALGRIND_MALLOC(ret != NULL, tsdn, ret, usize, false); JEMALLOC_VALGRIND_MALLOC(ret != NULL, tsdn, ret, usize, true);
} }
return (ret); return (ret);
@@ -1913,8 +1998,8 @@ je_realloc(void *ptr, size_t size)
*tsd_thread_deallocatedp_get(tsd) += old_usize; *tsd_thread_deallocatedp_get(tsd) += old_usize;
} }
UTRACE(ptr, size, ret); UTRACE(ptr, size, ret);
JEMALLOC_VALGRIND_REALLOC(true, tsdn, ret, usize, true, ptr, old_usize, JEMALLOC_VALGRIND_REALLOC(maybe, tsdn, ret, usize, maybe, ptr,
old_rzsize, true, false); old_usize, old_rzsize, maybe, false);
witness_assert_lockless(tsdn); witness_assert_lockless(tsdn);
return (ret); return (ret);
} }
@@ -1994,6 +2079,29 @@ JEMALLOC_EXPORT void *(*__realloc_hook)(void *ptr, size_t size) = je_realloc;
JEMALLOC_EXPORT void *(*__memalign_hook)(size_t alignment, size_t size) = JEMALLOC_EXPORT void *(*__memalign_hook)(size_t alignment, size_t size) =
je_memalign; je_memalign;
# endif # endif
#ifdef CPU_COUNT
/*
* To enable static linking with glibc, the libc specific malloc interface must
* be implemented also, so none of glibc's malloc.o functions are added to the
* link.
*/
#define ALIAS(je_fn) __attribute__((alias (#je_fn), used))
/* To force macro expansion of je_ prefix before stringification. */
#define PREALIAS(je_fn) ALIAS(je_fn)
void *__libc_malloc(size_t size) PREALIAS(je_malloc);
void __libc_free(void* ptr) PREALIAS(je_free);
void *__libc_realloc(void* ptr, size_t size) PREALIAS(je_realloc);
void *__libc_calloc(size_t n, size_t size) PREALIAS(je_calloc);
void *__libc_memalign(size_t align, size_t s) PREALIAS(je_memalign);
void *__libc_valloc(size_t size) PREALIAS(je_valloc);
int __posix_memalign(void** r, size_t a, size_t s)
PREALIAS(je_posix_memalign);
#undef PREALIAS
#undef ALIAS
#endif
#endif #endif
/* /*
@@ -2222,7 +2330,7 @@ irallocx_prof(tsd_t *tsd, void *old_ptr, size_t old_usize, size_t size,
prof_active = prof_active_get_unlocked(); prof_active = prof_active_get_unlocked();
old_tctx = prof_tctx_get(tsd_tsdn(tsd), old_ptr); old_tctx = prof_tctx_get(tsd_tsdn(tsd), old_ptr);
tctx = prof_alloc_prep(tsd, *usize, prof_active, true); tctx = prof_alloc_prep(tsd, *usize, prof_active, false);
if (unlikely((uintptr_t)tctx != (uintptr_t)1U)) { if (unlikely((uintptr_t)tctx != (uintptr_t)1U)) {
p = irallocx_prof_sample(tsd, old_ptr, old_usize, *usize, p = irallocx_prof_sample(tsd, old_ptr, old_usize, *usize,
alignment, zero, tcache, arena, tctx); alignment, zero, tcache, arena, tctx);
@@ -2231,7 +2339,7 @@ irallocx_prof(tsd_t *tsd, void *old_ptr, size_t old_usize, size_t size,
tcache, arena); tcache, arena);
} }
if (unlikely(p == NULL)) { if (unlikely(p == NULL)) {
prof_alloc_rollback(tsd, tctx, true); prof_alloc_rollback(tsd, tctx, false);
return (NULL); return (NULL);
} }
@@ -2246,7 +2354,7 @@ irallocx_prof(tsd_t *tsd, void *old_ptr, size_t old_usize, size_t size,
*/ */
*usize = isalloc(tsd_tsdn(tsd), p, config_prof); *usize = isalloc(tsd_tsdn(tsd), p, config_prof);
} }
prof_realloc(tsd, p, *usize, tctx, prof_active, true, old_ptr, prof_realloc(tsd, p, *usize, tctx, prof_active, false, old_ptr,
old_usize, old_tctx); old_usize, old_tctx);
return (p); return (p);
@@ -2317,8 +2425,8 @@ je_rallocx(void *ptr, size_t size, int flags)
*tsd_thread_deallocatedp_get(tsd) += old_usize; *tsd_thread_deallocatedp_get(tsd) += old_usize;
} }
UTRACE(ptr, size, p); UTRACE(ptr, size, p);
JEMALLOC_VALGRIND_REALLOC(true, tsd_tsdn(tsd), p, usize, false, ptr, JEMALLOC_VALGRIND_REALLOC(maybe, tsd_tsdn(tsd), p, usize, no, ptr,
old_usize, old_rzsize, false, zero); old_usize, old_rzsize, no, zero);
witness_assert_lockless(tsd_tsdn(tsd)); witness_assert_lockless(tsd_tsdn(tsd));
return (p); return (p);
label_oom: label_oom:
@@ -2460,8 +2568,8 @@ je_xallocx(void *ptr, size_t size, size_t extra, int flags)
*tsd_thread_allocatedp_get(tsd) += usize; *tsd_thread_allocatedp_get(tsd) += usize;
*tsd_thread_deallocatedp_get(tsd) += old_usize; *tsd_thread_deallocatedp_get(tsd) += old_usize;
} }
JEMALLOC_VALGRIND_REALLOC(false, tsd_tsdn(tsd), ptr, usize, false, ptr, JEMALLOC_VALGRIND_REALLOC(no, tsd_tsdn(tsd), ptr, usize, no, ptr,
old_usize, old_rzsize, false, zero); old_usize, old_rzsize, no, zero);
label_not_resized: label_not_resized:
UTRACE(ptr, size, ptr); UTRACE(ptr, size, ptr);
witness_assert_lockless(tsd_tsdn(tsd)); witness_assert_lockless(tsd_tsdn(tsd));
@@ -2725,6 +2833,7 @@ _malloc_prefork(void)
witness_prefork(tsd); witness_prefork(tsd);
/* Acquire all mutexes in a safe order. */ /* Acquire all mutexes in a safe order. */
ctl_prefork(tsd_tsdn(tsd)); ctl_prefork(tsd_tsdn(tsd));
tcache_prefork(tsd_tsdn(tsd));
malloc_mutex_prefork(tsd_tsdn(tsd), &arenas_lock); malloc_mutex_prefork(tsd_tsdn(tsd), &arenas_lock);
prof_prefork0(tsd_tsdn(tsd)); prof_prefork0(tsd_tsdn(tsd));
for (i = 0; i < 3; i++) { for (i = 0; i < 3; i++) {
@@ -2747,7 +2856,6 @@ _malloc_prefork(void)
} }
} }
base_prefork(tsd_tsdn(tsd)); base_prefork(tsd_tsdn(tsd));
chunk_prefork(tsd_tsdn(tsd));
for (i = 0; i < narenas; i++) { for (i = 0; i < narenas; i++) {
if ((arena = arena_get(tsd_tsdn(tsd), i, false)) != NULL) if ((arena = arena_get(tsd_tsdn(tsd), i, false)) != NULL)
arena_prefork3(tsd_tsdn(tsd), arena); arena_prefork3(tsd_tsdn(tsd), arena);
@@ -2776,7 +2884,6 @@ _malloc_postfork(void)
witness_postfork_parent(tsd); witness_postfork_parent(tsd);
/* Release all mutexes, now that fork() has completed. */ /* Release all mutexes, now that fork() has completed. */
chunk_postfork_parent(tsd_tsdn(tsd));
base_postfork_parent(tsd_tsdn(tsd)); base_postfork_parent(tsd_tsdn(tsd));
for (i = 0, narenas = narenas_total_get(); i < narenas; i++) { for (i = 0, narenas = narenas_total_get(); i < narenas; i++) {
arena_t *arena; arena_t *arena;
@@ -2786,6 +2893,7 @@ _malloc_postfork(void)
} }
prof_postfork_parent(tsd_tsdn(tsd)); prof_postfork_parent(tsd_tsdn(tsd));
malloc_mutex_postfork_parent(tsd_tsdn(tsd), &arenas_lock); malloc_mutex_postfork_parent(tsd_tsdn(tsd), &arenas_lock);
tcache_postfork_parent(tsd_tsdn(tsd));
ctl_postfork_parent(tsd_tsdn(tsd)); ctl_postfork_parent(tsd_tsdn(tsd));
} }
@@ -2801,7 +2909,6 @@ jemalloc_postfork_child(void)
witness_postfork_child(tsd); witness_postfork_child(tsd);
/* Release all mutexes, now that fork() has completed. */ /* Release all mutexes, now that fork() has completed. */
chunk_postfork_child(tsd_tsdn(tsd));
base_postfork_child(tsd_tsdn(tsd)); base_postfork_child(tsd_tsdn(tsd));
for (i = 0, narenas = narenas_total_get(); i < narenas; i++) { for (i = 0, narenas = narenas_total_get(); i < narenas; i++) {
arena_t *arena; arena_t *arena;
@@ -2811,6 +2918,7 @@ jemalloc_postfork_child(void)
} }
prof_postfork_child(tsd_tsdn(tsd)); prof_postfork_child(tsd_tsdn(tsd));
malloc_mutex_postfork_child(tsd_tsdn(tsd), &arenas_lock); malloc_mutex_postfork_child(tsd_tsdn(tsd), &arenas_lock);
tcache_postfork_child(tsd_tsdn(tsd));
ctl_postfork_child(tsd_tsdn(tsd)); ctl_postfork_child(tsd_tsdn(tsd));
} }

View File

@@ -80,6 +80,8 @@ malloc_mutex_init(malloc_mutex_t *mutex, const char *name, witness_rank_t rank)
_CRT_SPINCOUNT)) _CRT_SPINCOUNT))
return (true); return (true);
# endif # endif
#elif (defined(JEMALLOC_OS_UNFAIR_LOCK))
mutex->lock = OS_UNFAIR_LOCK_INIT;
#elif (defined(JEMALLOC_OSSPIN)) #elif (defined(JEMALLOC_OSSPIN))
mutex->lock = 0; mutex->lock = 0;
#elif (defined(JEMALLOC_MUTEX_INIT_CB)) #elif (defined(JEMALLOC_MUTEX_INIT_CB))

View File

@@ -97,6 +97,76 @@ nstime_divide(const nstime_t *time, const nstime_t *divisor)
return (time->ns / divisor->ns); return (time->ns / divisor->ns);
} }
#ifdef _WIN32
# define NSTIME_MONOTONIC true
static void
nstime_get(nstime_t *time)
{
FILETIME ft;
uint64_t ticks_100ns;
GetSystemTimeAsFileTime(&ft);
ticks_100ns = (((uint64_t)ft.dwHighDateTime) << 32) | ft.dwLowDateTime;
nstime_init(time, ticks_100ns * 100);
}
#elif JEMALLOC_HAVE_CLOCK_MONOTONIC_COARSE
# define NSTIME_MONOTONIC true
static void
nstime_get(nstime_t *time)
{
struct timespec ts;
clock_gettime(CLOCK_MONOTONIC_COARSE, &ts);
nstime_init2(time, ts.tv_sec, ts.tv_nsec);
}
#elif JEMALLOC_HAVE_CLOCK_MONOTONIC
# define NSTIME_MONOTONIC true
static void
nstime_get(nstime_t *time)
{
struct timespec ts;
clock_gettime(CLOCK_MONOTONIC, &ts);
nstime_init2(time, ts.tv_sec, ts.tv_nsec);
}
#elif JEMALLOC_HAVE_MACH_ABSOLUTE_TIME
# define NSTIME_MONOTONIC true
static void
nstime_get(nstime_t *time)
{
nstime_init(time, mach_absolute_time());
}
#else
# define NSTIME_MONOTONIC false
static void
nstime_get(nstime_t *time)
{
struct timeval tv;
gettimeofday(&tv, NULL);
nstime_init2(time, tv.tv_sec, tv.tv_usec * 1000);
}
#endif
#ifdef JEMALLOC_JET
#undef nstime_monotonic
#define nstime_monotonic JEMALLOC_N(n_nstime_monotonic)
#endif
bool
nstime_monotonic(void)
{
return (NSTIME_MONOTONIC);
#undef NSTIME_MONOTONIC
}
#ifdef JEMALLOC_JET
#undef nstime_monotonic
#define nstime_monotonic JEMALLOC_N(nstime_monotonic)
nstime_monotonic_t *nstime_monotonic = JEMALLOC_N(n_nstime_monotonic);
#endif
#ifdef JEMALLOC_JET #ifdef JEMALLOC_JET
#undef nstime_update #undef nstime_update
#define nstime_update JEMALLOC_N(n_nstime_update) #define nstime_update JEMALLOC_N(n_nstime_update)
@@ -107,31 +177,7 @@ nstime_update(nstime_t *time)
nstime_t old_time; nstime_t old_time;
nstime_copy(&old_time, time); nstime_copy(&old_time, time);
nstime_get(time);
#ifdef _WIN32
{
FILETIME ft;
uint64_t ticks;
GetSystemTimeAsFileTime(&ft);
ticks = (((uint64_t)ft.dwHighDateTime) << 32) |
ft.dwLowDateTime;
time->ns = ticks * 100;
}
#elif JEMALLOC_CLOCK_GETTIME
{
struct timespec ts;
if (sysconf(_SC_MONOTONIC_CLOCK) > 0)
clock_gettime(CLOCK_MONOTONIC, &ts);
else
clock_gettime(CLOCK_REALTIME, &ts);
time->ns = ts.tv_sec * BILLION + ts.tv_nsec;
}
#else
struct timeval tv;
gettimeofday(&tv, NULL);
time->ns = tv.tv_sec * BILLION + tv.tv_usec * 1000;
#endif
/* Handle non-monotonic clocks. */ /* Handle non-monotonic clocks. */
if (unlikely(nstime_compare(&old_time, time) > 0)) { if (unlikely(nstime_compare(&old_time, time) > 0)) {

View File

@@ -170,15 +170,16 @@ pages_purge(void *addr, size_t size)
#ifdef _WIN32 #ifdef _WIN32
VirtualAlloc(addr, size, MEM_RESET, PAGE_READWRITE); VirtualAlloc(addr, size, MEM_RESET, PAGE_READWRITE);
unzeroed = true; unzeroed = true;
#elif defined(JEMALLOC_HAVE_MADVISE) #elif (defined(JEMALLOC_PURGE_MADVISE_FREE) || \
# ifdef JEMALLOC_PURGE_MADVISE_DONTNEED defined(JEMALLOC_PURGE_MADVISE_DONTNEED))
# define JEMALLOC_MADV_PURGE MADV_DONTNEED # if defined(JEMALLOC_PURGE_MADVISE_FREE)
# define JEMALLOC_MADV_ZEROS true
# elif defined(JEMALLOC_PURGE_MADVISE_FREE)
# define JEMALLOC_MADV_PURGE MADV_FREE # define JEMALLOC_MADV_PURGE MADV_FREE
# define JEMALLOC_MADV_ZEROS false # define JEMALLOC_MADV_ZEROS false
# elif defined(JEMALLOC_PURGE_MADVISE_DONTNEED)
# define JEMALLOC_MADV_PURGE MADV_DONTNEED
# define JEMALLOC_MADV_ZEROS true
# else # else
# error "No madvise(2) flag defined for purging unused dirty pages." # error No madvise(2) flag defined for purging unused dirty pages
# endif # endif
int err = madvise(addr, size, JEMALLOC_MADV_PURGE); int err = madvise(addr, size, JEMALLOC_MADV_PURGE);
unzeroed = (!JEMALLOC_MADV_ZEROS || err != 0); unzeroed = (!JEMALLOC_MADV_ZEROS || err != 0);
@@ -191,6 +192,34 @@ pages_purge(void *addr, size_t size)
return (unzeroed); return (unzeroed);
} }
bool
pages_huge(void *addr, size_t size)
{
assert(PAGE_ADDR2BASE(addr) == addr);
assert(PAGE_CEILING(size) == size);
#ifdef JEMALLOC_HAVE_MADVISE_HUGE
return (madvise(addr, size, MADV_HUGEPAGE) != 0);
#else
return (false);
#endif
}
bool
pages_nohuge(void *addr, size_t size)
{
assert(PAGE_ADDR2BASE(addr) == addr);
assert(PAGE_CEILING(size) == size);
#ifdef JEMALLOC_HAVE_MADVISE_HUGE
return (madvise(addr, size, MADV_NOHUGEPAGE) != 0);
#else
return (false);
#endif
}
#ifdef JEMALLOC_SYSCTL_VM_OVERCOMMIT #ifdef JEMALLOC_SYSCTL_VM_OVERCOMMIT
static bool static bool
os_overcommits_sysctl(void) os_overcommits_sysctl(void)
@@ -207,6 +236,11 @@ os_overcommits_sysctl(void)
#endif #endif
#ifdef JEMALLOC_PROC_SYS_VM_OVERCOMMIT_MEMORY #ifdef JEMALLOC_PROC_SYS_VM_OVERCOMMIT_MEMORY
/*
* Use syscall(2) rather than {open,read,close}(2) when possible to avoid
* reentry during bootstrapping if another library has interposed system call
* wrappers.
*/
static bool static bool
os_overcommits_proc(void) os_overcommits_proc(void)
{ {
@@ -214,11 +248,29 @@ os_overcommits_proc(void)
char buf[1]; char buf[1];
ssize_t nread; ssize_t nread;
#if defined(JEMALLOC_USE_SYSCALL) && defined(SYS_open)
fd = (int)syscall(SYS_open, "/proc/sys/vm/overcommit_memory", O_RDONLY);
#elif defined(JEMALLOC_USE_SYSCALL) && defined(SYS_openat)
fd = (int)syscall(SYS_openat,
AT_FDCWD, "/proc/sys/vm/overcommit_memory", O_RDONLY);
#else
fd = open("/proc/sys/vm/overcommit_memory", O_RDONLY); fd = open("/proc/sys/vm/overcommit_memory", O_RDONLY);
#endif
if (fd == -1) if (fd == -1)
return (false); /* Error. */ return (false); /* Error. */
#if defined(JEMALLOC_USE_SYSCALL) && defined(SYS_read)
nread = (ssize_t)syscall(SYS_read, fd, &buf, sizeof(buf));
#else
nread = read(fd, &buf, sizeof(buf)); nread = read(fd, &buf, sizeof(buf));
#endif
#if defined(JEMALLOC_USE_SYSCALL) && defined(SYS_close)
syscall(SYS_close, fd);
#else
close(fd);
#endif
if (nread < 1) if (nread < 1)
return (false); /* Error. */ return (false); /* Error. */
/* /*

View File

@@ -125,7 +125,7 @@ static bool prof_tctx_should_destroy(tsdn_t *tsdn, prof_tctx_t *tctx);
static void prof_tctx_destroy(tsd_t *tsd, prof_tctx_t *tctx); static void prof_tctx_destroy(tsd_t *tsd, prof_tctx_t *tctx);
static bool prof_tdata_should_destroy(tsdn_t *tsdn, prof_tdata_t *tdata, static bool prof_tdata_should_destroy(tsdn_t *tsdn, prof_tdata_t *tdata,
bool even_if_attached); bool even_if_attached);
static void prof_tdata_destroy(tsdn_t *tsdn, prof_tdata_t *tdata, static void prof_tdata_destroy(tsd_t *tsd, prof_tdata_t *tdata,
bool even_if_attached); bool even_if_attached);
static char *prof_thread_name_alloc(tsdn_t *tsdn, const char *thread_name); static char *prof_thread_name_alloc(tsdn_t *tsdn, const char *thread_name);
@@ -591,7 +591,7 @@ prof_gctx_try_destroy(tsd_t *tsd, prof_tdata_t *tdata_self, prof_gctx_t *gctx,
assert(gctx->nlimbo != 0); assert(gctx->nlimbo != 0);
if (tctx_tree_empty(&gctx->tctxs) && gctx->nlimbo == 1) { if (tctx_tree_empty(&gctx->tctxs) && gctx->nlimbo == 1) {
/* Remove gctx from bt2gctx. */ /* Remove gctx from bt2gctx. */
if (ckh_remove(tsd_tsdn(tsd), &bt2gctx, &gctx->bt, NULL, NULL)) if (ckh_remove(tsd, &bt2gctx, &gctx->bt, NULL, NULL))
not_reached(); not_reached();
prof_leave(tsd, tdata_self); prof_leave(tsd, tdata_self);
/* Destroy gctx. */ /* Destroy gctx. */
@@ -651,7 +651,7 @@ prof_tctx_destroy(tsd_t *tsd, prof_tctx_t *tctx)
assert(tctx->cnts.accumobjs == 0); assert(tctx->cnts.accumobjs == 0);
assert(tctx->cnts.accumbytes == 0); assert(tctx->cnts.accumbytes == 0);
ckh_remove(tsd_tsdn(tsd), &tdata->bt2tctx, &gctx->bt, NULL, NULL); ckh_remove(tsd, &tdata->bt2tctx, &gctx->bt, NULL, NULL);
destroy_tdata = prof_tdata_should_destroy(tsd_tsdn(tsd), tdata, false); destroy_tdata = prof_tdata_should_destroy(tsd_tsdn(tsd), tdata, false);
malloc_mutex_unlock(tsd_tsdn(tsd), tdata->lock); malloc_mutex_unlock(tsd_tsdn(tsd), tdata->lock);
@@ -704,7 +704,7 @@ prof_tctx_destroy(tsd_t *tsd, prof_tctx_t *tctx)
malloc_mutex_assert_not_owner(tsd_tsdn(tsd), tctx->tdata->lock); malloc_mutex_assert_not_owner(tsd_tsdn(tsd), tctx->tdata->lock);
if (destroy_tdata) if (destroy_tdata)
prof_tdata_destroy(tsd_tsdn(tsd), tdata, false); prof_tdata_destroy(tsd, tdata, false);
if (destroy_tctx) if (destroy_tctx)
idalloctm(tsd_tsdn(tsd), tctx, NULL, true, true); idalloctm(tsd_tsdn(tsd), tctx, NULL, true, true);
@@ -733,7 +733,7 @@ prof_lookup_global(tsd_t *tsd, prof_bt_t *bt, prof_tdata_t *tdata,
return (true); return (true);
} }
btkey.p = &gctx.p->bt; btkey.p = &gctx.p->bt;
if (ckh_insert(tsd_tsdn(tsd), &bt2gctx, btkey.v, gctx.v)) { if (ckh_insert(tsd, &bt2gctx, btkey.v, gctx.v)) {
/* OOM. */ /* OOM. */
prof_leave(tsd, tdata); prof_leave(tsd, tdata);
idalloctm(tsd_tsdn(tsd), gctx.v, NULL, true, true); idalloctm(tsd_tsdn(tsd), gctx.v, NULL, true, true);
@@ -795,7 +795,7 @@ prof_lookup(tsd_t *tsd, prof_bt_t *bt)
/* Link a prof_tctx_t into gctx for this thread. */ /* Link a prof_tctx_t into gctx for this thread. */
ret.v = iallocztm(tsd_tsdn(tsd), sizeof(prof_tctx_t), ret.v = iallocztm(tsd_tsdn(tsd), sizeof(prof_tctx_t),
size2index(sizeof(prof_tctx_t)), false, NULL, true, size2index(sizeof(prof_tctx_t)), false, NULL, true,
arena_ichoose(tsd_tsdn(tsd), NULL), true); arena_ichoose(tsd, NULL), true);
if (ret.p == NULL) { if (ret.p == NULL) {
if (new_gctx) if (new_gctx)
prof_gctx_try_destroy(tsd, tdata, gctx, tdata); prof_gctx_try_destroy(tsd, tdata, gctx, tdata);
@@ -810,8 +810,7 @@ prof_lookup(tsd_t *tsd, prof_bt_t *bt)
ret.p->prepared = true; ret.p->prepared = true;
ret.p->state = prof_tctx_state_initializing; ret.p->state = prof_tctx_state_initializing;
malloc_mutex_lock(tsd_tsdn(tsd), tdata->lock); malloc_mutex_lock(tsd_tsdn(tsd), tdata->lock);
error = ckh_insert(tsd_tsdn(tsd), &tdata->bt2tctx, btkey, error = ckh_insert(tsd, &tdata->bt2tctx, btkey, ret.v);
ret.v);
malloc_mutex_unlock(tsd_tsdn(tsd), tdata->lock); malloc_mutex_unlock(tsd_tsdn(tsd), tdata->lock);
if (error) { if (error) {
if (new_gctx) if (new_gctx)
@@ -875,7 +874,7 @@ prof_sample_threshold_update(prof_tdata_t *tdata)
* pp 500 * pp 500
* (http://luc.devroye.org/rnbookindex.html) * (http://luc.devroye.org/rnbookindex.html)
*/ */
r = prng_lg_range(&tdata->prng_state, 53); r = prng_lg_range_u64(&tdata->prng_state, 53);
u = (double)r * (1.0/9007199254740992.0L); u = (double)r * (1.0/9007199254740992.0L);
tdata->bytes_until_sample = (uint64_t)(log(u) / tdata->bytes_until_sample = (uint64_t)(log(u) /
log(1.0 - (1.0 / (double)((uint64_t)1U << lg_prof_sample)))) log(1.0 - (1.0 / (double)((uint64_t)1U << lg_prof_sample))))
@@ -1791,7 +1790,7 @@ prof_thr_uid_alloc(tsdn_t *tsdn)
} }
static prof_tdata_t * static prof_tdata_t *
prof_tdata_init_impl(tsdn_t *tsdn, uint64_t thr_uid, uint64_t thr_discrim, prof_tdata_init_impl(tsd_t *tsd, uint64_t thr_uid, uint64_t thr_discrim,
char *thread_name, bool active) char *thread_name, bool active)
{ {
prof_tdata_t *tdata; prof_tdata_t *tdata;
@@ -1799,7 +1798,7 @@ prof_tdata_init_impl(tsdn_t *tsdn, uint64_t thr_uid, uint64_t thr_discrim,
cassert(config_prof); cassert(config_prof);
/* Initialize an empty cache for this thread. */ /* Initialize an empty cache for this thread. */
tdata = (prof_tdata_t *)iallocztm(tsdn, sizeof(prof_tdata_t), tdata = (prof_tdata_t *)iallocztm(tsd_tsdn(tsd), sizeof(prof_tdata_t),
size2index(sizeof(prof_tdata_t)), false, NULL, true, size2index(sizeof(prof_tdata_t)), false, NULL, true,
arena_get(TSDN_NULL, 0, true), true); arena_get(TSDN_NULL, 0, true), true);
if (tdata == NULL) if (tdata == NULL)
@@ -1813,9 +1812,9 @@ prof_tdata_init_impl(tsdn_t *tsdn, uint64_t thr_uid, uint64_t thr_discrim,
tdata->expired = false; tdata->expired = false;
tdata->tctx_uid_next = 0; tdata->tctx_uid_next = 0;
if (ckh_new(tsdn, &tdata->bt2tctx, PROF_CKH_MINITEMS, if (ckh_new(tsd, &tdata->bt2tctx, PROF_CKH_MINITEMS, prof_bt_hash,
prof_bt_hash, prof_bt_keycomp)) { prof_bt_keycomp)) {
idalloctm(tsdn, tdata, NULL, true, true); idalloctm(tsd_tsdn(tsd), tdata, NULL, true, true);
return (NULL); return (NULL);
} }
@@ -1829,19 +1828,19 @@ prof_tdata_init_impl(tsdn_t *tsdn, uint64_t thr_uid, uint64_t thr_discrim,
tdata->dumping = false; tdata->dumping = false;
tdata->active = active; tdata->active = active;
malloc_mutex_lock(tsdn, &tdatas_mtx); malloc_mutex_lock(tsd_tsdn(tsd), &tdatas_mtx);
tdata_tree_insert(&tdatas, tdata); tdata_tree_insert(&tdatas, tdata);
malloc_mutex_unlock(tsdn, &tdatas_mtx); malloc_mutex_unlock(tsd_tsdn(tsd), &tdatas_mtx);
return (tdata); return (tdata);
} }
prof_tdata_t * prof_tdata_t *
prof_tdata_init(tsdn_t *tsdn) prof_tdata_init(tsd_t *tsd)
{ {
return (prof_tdata_init_impl(tsdn, prof_thr_uid_alloc(tsdn), 0, NULL, return (prof_tdata_init_impl(tsd, prof_thr_uid_alloc(tsd_tsdn(tsd)), 0,
prof_thread_active_init_get(tsdn))); NULL, prof_thread_active_init_get(tsd_tsdn(tsd))));
} }
static bool static bool
@@ -1866,31 +1865,29 @@ prof_tdata_should_destroy(tsdn_t *tsdn, prof_tdata_t *tdata,
} }
static void static void
prof_tdata_destroy_locked(tsdn_t *tsdn, prof_tdata_t *tdata, prof_tdata_destroy_locked(tsd_t *tsd, prof_tdata_t *tdata,
bool even_if_attached) bool even_if_attached)
{ {
malloc_mutex_assert_owner(tsdn, &tdatas_mtx); malloc_mutex_assert_owner(tsd_tsdn(tsd), &tdatas_mtx);
assert(tsdn_null(tsdn) || tsd_prof_tdata_get(tsdn_tsd(tsdn)) != tdata);
tdata_tree_remove(&tdatas, tdata); tdata_tree_remove(&tdatas, tdata);
assert(prof_tdata_should_destroy_unlocked(tdata, even_if_attached)); assert(prof_tdata_should_destroy_unlocked(tdata, even_if_attached));
if (tdata->thread_name != NULL) if (tdata->thread_name != NULL)
idalloctm(tsdn, tdata->thread_name, NULL, true, true); idalloctm(tsd_tsdn(tsd), tdata->thread_name, NULL, true, true);
ckh_delete(tsdn, &tdata->bt2tctx); ckh_delete(tsd, &tdata->bt2tctx);
idalloctm(tsdn, tdata, NULL, true, true); idalloctm(tsd_tsdn(tsd), tdata, NULL, true, true);
} }
static void static void
prof_tdata_destroy(tsdn_t *tsdn, prof_tdata_t *tdata, bool even_if_attached) prof_tdata_destroy(tsd_t *tsd, prof_tdata_t *tdata, bool even_if_attached)
{ {
malloc_mutex_lock(tsdn, &tdatas_mtx); malloc_mutex_lock(tsd_tsdn(tsd), &tdatas_mtx);
prof_tdata_destroy_locked(tsdn, tdata, even_if_attached); prof_tdata_destroy_locked(tsd, tdata, even_if_attached);
malloc_mutex_unlock(tsdn, &tdatas_mtx); malloc_mutex_unlock(tsd_tsdn(tsd), &tdatas_mtx);
} }
static void static void
@@ -1913,7 +1910,7 @@ prof_tdata_detach(tsd_t *tsd, prof_tdata_t *tdata)
destroy_tdata = false; destroy_tdata = false;
malloc_mutex_unlock(tsd_tsdn(tsd), tdata->lock); malloc_mutex_unlock(tsd_tsdn(tsd), tdata->lock);
if (destroy_tdata) if (destroy_tdata)
prof_tdata_destroy(tsd_tsdn(tsd), tdata, true); prof_tdata_destroy(tsd, tdata, true);
} }
prof_tdata_t * prof_tdata_t *
@@ -1926,8 +1923,8 @@ prof_tdata_reinit(tsd_t *tsd, prof_tdata_t *tdata)
bool active = tdata->active; bool active = tdata->active;
prof_tdata_detach(tsd, tdata); prof_tdata_detach(tsd, tdata);
return (prof_tdata_init_impl(tsd_tsdn(tsd), thr_uid, thr_discrim, return (prof_tdata_init_impl(tsd, thr_uid, thr_discrim, thread_name,
thread_name, active)); active));
} }
static bool static bool
@@ -1956,30 +1953,30 @@ prof_tdata_reset_iter(prof_tdata_tree_t *tdatas, prof_tdata_t *tdata, void *arg)
} }
void void
prof_reset(tsdn_t *tsdn, size_t lg_sample) prof_reset(tsd_t *tsd, size_t lg_sample)
{ {
prof_tdata_t *next; prof_tdata_t *next;
assert(lg_sample < (sizeof(uint64_t) << 3)); assert(lg_sample < (sizeof(uint64_t) << 3));
malloc_mutex_lock(tsdn, &prof_dump_mtx); malloc_mutex_lock(tsd_tsdn(tsd), &prof_dump_mtx);
malloc_mutex_lock(tsdn, &tdatas_mtx); malloc_mutex_lock(tsd_tsdn(tsd), &tdatas_mtx);
lg_prof_sample = lg_sample; lg_prof_sample = lg_sample;
next = NULL; next = NULL;
do { do {
prof_tdata_t *to_destroy = tdata_tree_iter(&tdatas, next, prof_tdata_t *to_destroy = tdata_tree_iter(&tdatas, next,
prof_tdata_reset_iter, (void *)tsdn); prof_tdata_reset_iter, (void *)tsd);
if (to_destroy != NULL) { if (to_destroy != NULL) {
next = tdata_tree_next(&tdatas, to_destroy); next = tdata_tree_next(&tdatas, to_destroy);
prof_tdata_destroy_locked(tsdn, to_destroy, false); prof_tdata_destroy_locked(tsd, to_destroy, false);
} else } else
next = NULL; next = NULL;
} while (next != NULL); } while (next != NULL);
malloc_mutex_unlock(tsdn, &tdatas_mtx); malloc_mutex_unlock(tsd_tsdn(tsd), &tdatas_mtx);
malloc_mutex_unlock(tsdn, &prof_dump_mtx); malloc_mutex_unlock(tsd_tsdn(tsd), &prof_dump_mtx);
} }
void void
@@ -2189,7 +2186,7 @@ prof_boot1(void)
} }
bool bool
prof_boot2(tsdn_t *tsdn) prof_boot2(tsd_t *tsd)
{ {
cassert(config_prof); cassert(config_prof);
@@ -2215,7 +2212,7 @@ prof_boot2(tsdn_t *tsdn)
WITNESS_RANK_PROF_THREAD_ACTIVE_INIT)) WITNESS_RANK_PROF_THREAD_ACTIVE_INIT))
return (true); return (true);
if (ckh_new(tsdn, &bt2gctx, PROF_CKH_MINITEMS, prof_bt_hash, if (ckh_new(tsd, &bt2gctx, PROF_CKH_MINITEMS, prof_bt_hash,
prof_bt_keycomp)) prof_bt_keycomp))
return (true); return (true);
if (malloc_mutex_init(&bt2gctx_mtx, "prof_bt2gctx", if (malloc_mutex_init(&bt2gctx_mtx, "prof_bt2gctx",
@@ -2246,8 +2243,8 @@ prof_boot2(tsdn_t *tsdn)
abort(); abort();
} }
gctx_locks = (malloc_mutex_t *)base_alloc(tsdn, PROF_NCTX_LOCKS gctx_locks = (malloc_mutex_t *)base_alloc(tsd_tsdn(tsd),
* sizeof(malloc_mutex_t)); PROF_NCTX_LOCKS * sizeof(malloc_mutex_t));
if (gctx_locks == NULL) if (gctx_locks == NULL)
return (true); return (true);
for (i = 0; i < PROF_NCTX_LOCKS; i++) { for (i = 0; i < PROF_NCTX_LOCKS; i++) {
@@ -2256,7 +2253,7 @@ prof_boot2(tsdn_t *tsdn)
return (true); return (true);
} }
tdata_locks = (malloc_mutex_t *)base_alloc(tsdn, tdata_locks = (malloc_mutex_t *)base_alloc(tsd_tsdn(tsd),
PROF_NTDATA_LOCKS * sizeof(malloc_mutex_t)); PROF_NTDATA_LOCKS * sizeof(malloc_mutex_t));
if (tdata_locks == NULL) if (tdata_locks == NULL)
return (true); return (true);

View File

@@ -96,12 +96,15 @@ rtree_node_init(rtree_t *rtree, unsigned level, rtree_node_elm_t **elmp)
rtree_node_elm_t *node; rtree_node_elm_t *node;
if (atomic_cas_p((void **)elmp, NULL, RTREE_NODE_INITIALIZING)) { if (atomic_cas_p((void **)elmp, NULL, RTREE_NODE_INITIALIZING)) {
spin_t spinner;
/* /*
* Another thread is already in the process of initializing. * Another thread is already in the process of initializing.
* Spin-wait until initialization is complete. * Spin-wait until initialization is complete.
*/ */
spin_init(&spinner);
do { do {
CPU_SPINWAIT; spin_adaptive(&spinner);
node = atomic_read_p((void **)elmp); node = atomic_read_p((void **)elmp);
} while (node == RTREE_NODE_INITIALIZING); } while (node == RTREE_NODE_INITIALIZING);
} else { } else {
@@ -125,5 +128,5 @@ rtree_node_elm_t *
rtree_child_read_hard(rtree_t *rtree, rtree_node_elm_t *elm, unsigned level) rtree_child_read_hard(rtree_t *rtree, rtree_node_elm_t *elm, unsigned level)
{ {
return (rtree_node_init(rtree, level, &elm->child)); return (rtree_node_init(rtree, level+1, &elm->child));
} }

2
src/spin.c Normal file
View File

@@ -0,0 +1,2 @@
#define JEMALLOC_SPIN_C_
#include "jemalloc/internal/jemalloc_internal.h"

File diff suppressed because it is too large Load Diff

View File

@@ -21,6 +21,9 @@ static unsigned tcaches_past;
/* Head of singly linked list tracking available tcaches elements. */ /* Head of singly linked list tracking available tcaches elements. */
static tcaches_t *tcaches_avail; static tcaches_t *tcaches_avail;
/* Protects tcaches{,_past,_avail}. */
static malloc_mutex_t tcaches_mtx;
/******************************************************************************/ /******************************************************************************/
size_t size_t
@@ -444,29 +447,56 @@ tcache_stats_merge(tsdn_t *tsdn, tcache_t *tcache, arena_t *arena)
} }
} }
static bool
tcaches_create_prep(tsd_t *tsd) {
bool err;
malloc_mutex_lock(tsd_tsdn(tsd), &tcaches_mtx);
if (tcaches == NULL) {
tcaches = base_alloc(tsd_tsdn(tsd), sizeof(tcache_t *) *
(MALLOCX_TCACHE_MAX+1));
if (tcaches == NULL) {
err = true;
goto label_return;
}
}
if (tcaches_avail == NULL && tcaches_past > MALLOCX_TCACHE_MAX) {
err = true;
goto label_return;
}
err = false;
label_return:
malloc_mutex_unlock(tsd_tsdn(tsd), &tcaches_mtx);
return err;
}
bool bool
tcaches_create(tsdn_t *tsdn, unsigned *r_ind) tcaches_create(tsd_t *tsd, unsigned *r_ind) {
{ bool err;
arena_t *arena; arena_t *arena;
tcache_t *tcache; tcache_t *tcache;
tcaches_t *elm; tcaches_t *elm;
if (tcaches == NULL) { if (tcaches_create_prep(tsd)) {
tcaches = base_alloc(tsdn, sizeof(tcache_t *) * err = true;
(MALLOCX_TCACHE_MAX+1)); goto label_return;
if (tcaches == NULL)
return (true);
} }
if (tcaches_avail == NULL && tcaches_past > MALLOCX_TCACHE_MAX) arena = arena_ichoose(tsd, NULL);
return (true); if (unlikely(arena == NULL)) {
arena = arena_ichoose(tsdn, NULL); err = true;
if (unlikely(arena == NULL)) goto label_return;
return (true); }
tcache = tcache_create(tsdn, arena); tcache = tcache_create(tsd_tsdn(tsd), arena);
if (tcache == NULL) if (tcache == NULL) {
return (true); err = true;
goto label_return;
}
malloc_mutex_lock(tsd_tsdn(tsd), &tcaches_mtx);
if (tcaches_avail != NULL) { if (tcaches_avail != NULL) {
elm = tcaches_avail; elm = tcaches_avail;
tcaches_avail = tcaches_avail->next; tcaches_avail = tcaches_avail->next;
@@ -478,51 +508,64 @@ tcaches_create(tsdn_t *tsdn, unsigned *r_ind)
*r_ind = tcaches_past; *r_ind = tcaches_past;
tcaches_past++; tcaches_past++;
} }
malloc_mutex_unlock(tsd_tsdn(tsd), &tcaches_mtx);
return (false); err = false;
label_return:
malloc_mutex_assert_not_owner(tsd_tsdn(tsd), &tcaches_mtx);
return err;
} }
static void static void
tcaches_elm_flush(tsd_t *tsd, tcaches_t *elm) tcaches_elm_flush(tsd_t *tsd, tcaches_t *elm) {
{ malloc_mutex_assert_owner(tsd_tsdn(tsd), &tcaches_mtx);
if (elm->tcache == NULL) if (elm->tcache == NULL) {
return; return;
}
tcache_destroy(tsd, elm->tcache); tcache_destroy(tsd, elm->tcache);
elm->tcache = NULL; elm->tcache = NULL;
} }
void void
tcaches_flush(tsd_t *tsd, unsigned ind) tcaches_flush(tsd_t *tsd, unsigned ind) {
{ malloc_mutex_lock(tsd_tsdn(tsd), &tcaches_mtx);
tcaches_elm_flush(tsd, &tcaches[ind]); tcaches_elm_flush(tsd, &tcaches[ind]);
malloc_mutex_unlock(tsd_tsdn(tsd), &tcaches_mtx);
} }
void void
tcaches_destroy(tsd_t *tsd, unsigned ind) tcaches_destroy(tsd_t *tsd, unsigned ind) {
{ tcaches_t *elm;
tcaches_t *elm = &tcaches[ind];
malloc_mutex_lock(tsd_tsdn(tsd), &tcaches_mtx);
elm = &tcaches[ind];
tcaches_elm_flush(tsd, elm); tcaches_elm_flush(tsd, elm);
elm->next = tcaches_avail; elm->next = tcaches_avail;
tcaches_avail = elm; tcaches_avail = elm;
malloc_mutex_unlock(tsd_tsdn(tsd), &tcaches_mtx);
} }
bool bool
tcache_boot(tsdn_t *tsdn) tcache_boot(tsdn_t *tsdn) {
{
unsigned i; unsigned i;
cassert(config_tcache);
/* /*
* If necessary, clamp opt_lg_tcache_max, now that large_maxclass is * If necessary, clamp opt_lg_tcache_max, now that large_maxclass is
* known. * known.
*/ */
if (opt_lg_tcache_max < 0 || (1U << opt_lg_tcache_max) < SMALL_MAXCLASS) if (opt_lg_tcache_max < 0 || (ZU(1) << opt_lg_tcache_max) < SMALL_MAXCLASS)
tcache_maxclass = SMALL_MAXCLASS; tcache_maxclass = SMALL_MAXCLASS;
else if ((1U << opt_lg_tcache_max) > large_maxclass) else if ((ZU(1) << opt_lg_tcache_max) > large_maxclass)
tcache_maxclass = large_maxclass; tcache_maxclass = large_maxclass;
else else
tcache_maxclass = (1U << opt_lg_tcache_max); tcache_maxclass = (ZU(1) << opt_lg_tcache_max);
if (malloc_mutex_init(&tcaches_mtx, "tcaches", WITNESS_RANK_TCACHES)) {
return true;
}
nhbins = size2index(tcache_maxclass) + 1; nhbins = size2index(tcache_maxclass) + 1;
@@ -553,3 +596,24 @@ tcache_boot(tsdn_t *tsdn)
return (false); return (false);
} }
void
tcache_prefork(tsdn_t *tsdn) {
if (!config_prof && opt_tcache) {
malloc_mutex_prefork(tsdn, &tcaches_mtx);
}
}
void
tcache_postfork_parent(tsdn_t *tsdn) {
if (!config_prof && opt_tcache) {
malloc_mutex_postfork_parent(tsdn, &tcaches_mtx);
}
}
void
tcache_postfork_child(tsdn_t *tsdn) {
if (!config_prof && opt_tcache) {
malloc_mutex_postfork_child(tsdn, &tcaches_mtx);
}
}

View File

@@ -171,10 +171,10 @@ tsd_init_check_recursion(tsd_init_head_t *head, tsd_init_block_t *block)
tsd_init_block_t *iter; tsd_init_block_t *iter;
/* Check whether this thread has already inserted into the list. */ /* Check whether this thread has already inserted into the list. */
malloc_mutex_lock(NULL, &head->lock); malloc_mutex_lock(TSDN_NULL, &head->lock);
ql_foreach(iter, &head->blocks, link) { ql_foreach(iter, &head->blocks, link) {
if (iter->thread == self) { if (iter->thread == self) {
malloc_mutex_unlock(NULL, &head->lock); malloc_mutex_unlock(TSDN_NULL, &head->lock);
return (iter->data); return (iter->data);
} }
} }
@@ -182,7 +182,7 @@ tsd_init_check_recursion(tsd_init_head_t *head, tsd_init_block_t *block)
ql_elm_new(block, link); ql_elm_new(block, link);
block->thread = self; block->thread = self;
ql_tail_insert(&head->blocks, block, link); ql_tail_insert(&head->blocks, block, link);
malloc_mutex_unlock(NULL, &head->lock); malloc_mutex_unlock(TSDN_NULL, &head->lock);
return (NULL); return (NULL);
} }
@@ -190,8 +190,8 @@ void
tsd_init_finish(tsd_init_head_t *head, tsd_init_block_t *block) tsd_init_finish(tsd_init_head_t *head, tsd_init_block_t *block)
{ {
malloc_mutex_lock(NULL, &head->lock); malloc_mutex_lock(TSDN_NULL, &head->lock);
ql_remove(&head->blocks, block, link); ql_remove(&head->blocks, block, link);
malloc_mutex_unlock(NULL, &head->lock); malloc_mutex_unlock(TSDN_NULL, &head->lock);
} }
#endif #endif

View File

@@ -49,7 +49,7 @@ static void
wrtmessage(void *cbopaque, const char *s) wrtmessage(void *cbopaque, const char *s)
{ {
#ifdef SYS_write #if defined(JEMALLOC_USE_SYSCALL) && defined(SYS_write)
/* /*
* Use syscall(2) rather than write(2) when possible in order to avoid * Use syscall(2) rather than write(2) when possible in order to avoid
* the possibility of memory allocation within libc. This is necessary * the possibility of memory allocation within libc. This is necessary
@@ -200,7 +200,7 @@ malloc_strtoumax(const char *restrict nptr, char **restrict endptr, int base)
p++; p++;
} }
if (neg) if (neg)
ret = -ret; ret = (uintmax_t)(-((intmax_t)ret));
if (p == ns) { if (p == ns) {
/* No conversion performed. */ /* No conversion performed. */

View File

@@ -71,15 +71,16 @@ witness_not_owner_error_t *witness_not_owner_error =
#endif #endif
#ifdef JEMALLOC_JET #ifdef JEMALLOC_JET
#undef witness_lockless_error #undef witness_depth_error
#define witness_lockless_error JEMALLOC_N(n_witness_lockless_error) #define witness_depth_error JEMALLOC_N(n_witness_depth_error)
#endif #endif
void void
witness_lockless_error(const witness_list_t *witnesses) witness_depth_error(const witness_list_t *witnesses,
{ witness_rank_t rank_inclusive, unsigned depth) {
witness_t *w; witness_t *w;
malloc_printf("<jemalloc>: Should not own any locks:"); malloc_printf("<jemalloc>: Should own %u lock%s of rank >= %u:", depth,
(depth != 1) ? "s" : "", rank_inclusive);
ql_foreach(w, witnesses, link) { ql_foreach(w, witnesses, link) {
malloc_printf(" %s(%u)", w->name, w->rank); malloc_printf(" %s(%u)", w->name, w->rank);
} }
@@ -87,10 +88,9 @@ witness_lockless_error(const witness_list_t *witnesses)
abort(); abort();
} }
#ifdef JEMALLOC_JET #ifdef JEMALLOC_JET
#undef witness_lockless_error #undef witness_depth_error
#define witness_lockless_error JEMALLOC_N(witness_lockless_error) #define witness_depth_error JEMALLOC_N(witness_depth_error)
witness_lockless_error_t *witness_lockless_error = witness_depth_error_t *witness_depth_error = JEMALLOC_N(n_witness_depth_error);
JEMALLOC_N(n_witness_lockless_error);
#endif #endif
void void

View File

@@ -3,8 +3,77 @@
# error "This source file is for zones on Darwin (OS X)." # error "This source file is for zones on Darwin (OS X)."
#endif #endif
/* Definitions of the following structs in malloc/malloc.h might be too old
* for the built binary to run on newer versions of OSX. So use the newest
* possible version of those structs.
*/
typedef struct _malloc_zone_t {
void *reserved1;
void *reserved2;
size_t (*size)(struct _malloc_zone_t *, const void *);
void *(*malloc)(struct _malloc_zone_t *, size_t);
void *(*calloc)(struct _malloc_zone_t *, size_t, size_t);
void *(*valloc)(struct _malloc_zone_t *, size_t);
void (*free)(struct _malloc_zone_t *, void *);
void *(*realloc)(struct _malloc_zone_t *, void *, size_t);
void (*destroy)(struct _malloc_zone_t *);
const char *zone_name;
unsigned (*batch_malloc)(struct _malloc_zone_t *, size_t, void **, unsigned);
void (*batch_free)(struct _malloc_zone_t *, void **, unsigned);
struct malloc_introspection_t *introspect;
unsigned version;
void *(*memalign)(struct _malloc_zone_t *, size_t, size_t);
void (*free_definite_size)(struct _malloc_zone_t *, void *, size_t);
size_t (*pressure_relief)(struct _malloc_zone_t *, size_t);
} malloc_zone_t;
typedef struct {
vm_address_t address;
vm_size_t size;
} vm_range_t;
typedef struct malloc_statistics_t {
unsigned blocks_in_use;
size_t size_in_use;
size_t max_size_in_use;
size_t size_allocated;
} malloc_statistics_t;
typedef kern_return_t memory_reader_t(task_t, vm_address_t, vm_size_t, void **);
typedef void vm_range_recorder_t(task_t, void *, unsigned type, vm_range_t *, unsigned);
typedef struct malloc_introspection_t {
kern_return_t (*enumerator)(task_t, void *, unsigned, vm_address_t, memory_reader_t, vm_range_recorder_t);
size_t (*good_size)(malloc_zone_t *, size_t);
boolean_t (*check)(malloc_zone_t *);
void (*print)(malloc_zone_t *, boolean_t);
void (*log)(malloc_zone_t *, void *);
void (*force_lock)(malloc_zone_t *);
void (*force_unlock)(malloc_zone_t *);
void (*statistics)(malloc_zone_t *, malloc_statistics_t *);
boolean_t (*zone_locked)(malloc_zone_t *);
boolean_t (*enable_discharge_checking)(malloc_zone_t *);
boolean_t (*disable_discharge_checking)(malloc_zone_t *);
void (*discharge)(malloc_zone_t *, void *);
#ifdef __BLOCKS__
void (*enumerate_discharged_pointers)(malloc_zone_t *, void (^)(void *, void *));
#else
void *enumerate_unavailable_without_blocks;
#endif
void (*reinit_lock)(malloc_zone_t *);
} malloc_introspection_t;
extern kern_return_t malloc_get_all_zones(task_t, memory_reader_t, vm_address_t **, unsigned *);
extern malloc_zone_t *malloc_default_zone(void);
extern void malloc_zone_register(malloc_zone_t *zone);
extern void malloc_zone_unregister(malloc_zone_t *zone);
/* /*
* The malloc_default_purgeable_zone function is only available on >= 10.6. * The malloc_default_purgeable_zone() function is only available on >= 10.6.
* We need to check whether it is present at runtime, thus the weak_import. * We need to check whether it is present at runtime, thus the weak_import.
*/ */
extern malloc_zone_t *malloc_default_purgeable_zone(void) extern malloc_zone_t *malloc_default_purgeable_zone(void)
@@ -13,30 +82,42 @@ JEMALLOC_ATTR(weak_import);
/******************************************************************************/ /******************************************************************************/
/* Data. */ /* Data. */
static malloc_zone_t zone; static malloc_zone_t *default_zone, *purgeable_zone;
static struct malloc_introspection_t zone_introspect; static malloc_zone_t jemalloc_zone;
static struct malloc_introspection_t jemalloc_zone_introspect;
/******************************************************************************/ /******************************************************************************/
/* Function prototypes for non-inline static functions. */ /* Function prototypes for non-inline static functions. */
static size_t zone_size(malloc_zone_t *zone, void *ptr); static size_t zone_size(malloc_zone_t *zone, const void *ptr);
static void *zone_malloc(malloc_zone_t *zone, size_t size); static void *zone_malloc(malloc_zone_t *zone, size_t size);
static void *zone_calloc(malloc_zone_t *zone, size_t num, size_t size); static void *zone_calloc(malloc_zone_t *zone, size_t num, size_t size);
static void *zone_valloc(malloc_zone_t *zone, size_t size); static void *zone_valloc(malloc_zone_t *zone, size_t size);
static void zone_free(malloc_zone_t *zone, void *ptr); static void zone_free(malloc_zone_t *zone, void *ptr);
static void *zone_realloc(malloc_zone_t *zone, void *ptr, size_t size); static void *zone_realloc(malloc_zone_t *zone, void *ptr, size_t size);
#if (JEMALLOC_ZONE_VERSION >= 5)
static void *zone_memalign(malloc_zone_t *zone, size_t alignment, static void *zone_memalign(malloc_zone_t *zone, size_t alignment,
#endif
#if (JEMALLOC_ZONE_VERSION >= 6)
size_t size); size_t size);
static void zone_free_definite_size(malloc_zone_t *zone, void *ptr, static void zone_free_definite_size(malloc_zone_t *zone, void *ptr,
size_t size); size_t size);
#endif static void zone_destroy(malloc_zone_t *zone);
static void *zone_destroy(malloc_zone_t *zone); static unsigned zone_batch_malloc(struct _malloc_zone_t *zone, size_t size,
void **results, unsigned num_requested);
static void zone_batch_free(struct _malloc_zone_t *zone,
void **to_be_freed, unsigned num_to_be_freed);
static size_t zone_pressure_relief(struct _malloc_zone_t *zone, size_t goal);
static size_t zone_good_size(malloc_zone_t *zone, size_t size); static size_t zone_good_size(malloc_zone_t *zone, size_t size);
static kern_return_t zone_enumerator(task_t task, void *data, unsigned type_mask,
vm_address_t zone_address, memory_reader_t reader,
vm_range_recorder_t recorder);
static boolean_t zone_check(malloc_zone_t *zone);
static void zone_print(malloc_zone_t *zone, boolean_t verbose);
static void zone_log(malloc_zone_t *zone, void *address);
static void zone_force_lock(malloc_zone_t *zone); static void zone_force_lock(malloc_zone_t *zone);
static void zone_force_unlock(malloc_zone_t *zone); static void zone_force_unlock(malloc_zone_t *zone);
static void zone_statistics(malloc_zone_t *zone,
malloc_statistics_t *stats);
static boolean_t zone_locked(malloc_zone_t *zone);
static void zone_reinit_lock(malloc_zone_t *zone);
/******************************************************************************/ /******************************************************************************/
/* /*
@@ -44,7 +125,7 @@ static void zone_force_unlock(malloc_zone_t *zone);
*/ */
static size_t static size_t
zone_size(malloc_zone_t *zone, void *ptr) zone_size(malloc_zone_t *zone, const void *ptr)
{ {
/* /*
@@ -105,7 +186,6 @@ zone_realloc(malloc_zone_t *zone, void *ptr, size_t size)
return (realloc(ptr, size)); return (realloc(ptr, size));
} }
#if (JEMALLOC_ZONE_VERSION >= 5)
static void * static void *
zone_memalign(malloc_zone_t *zone, size_t alignment, size_t size) zone_memalign(malloc_zone_t *zone, size_t alignment, size_t size)
{ {
@@ -115,9 +195,7 @@ zone_memalign(malloc_zone_t *zone, size_t alignment, size_t size)
return (ret); return (ret);
} }
#endif
#if (JEMALLOC_ZONE_VERSION >= 6)
static void static void
zone_free_definite_size(malloc_zone_t *zone, void *ptr, size_t size) zone_free_definite_size(malloc_zone_t *zone, void *ptr, size_t size)
{ {
@@ -132,15 +210,46 @@ zone_free_definite_size(malloc_zone_t *zone, void *ptr, size_t size)
free(ptr); free(ptr);
} }
#endif
static void * static void
zone_destroy(malloc_zone_t *zone) zone_destroy(malloc_zone_t *zone)
{ {
/* This function should never be called. */ /* This function should never be called. */
not_reached(); not_reached();
return (NULL); }
static unsigned
zone_batch_malloc(struct _malloc_zone_t *zone, size_t size, void **results,
unsigned num_requested)
{
unsigned i;
for (i = 0; i < num_requested; i++) {
results[i] = je_malloc(size);
if (!results[i])
break;
}
return i;
}
static void
zone_batch_free(struct _malloc_zone_t *zone, void **to_be_freed,
unsigned num_to_be_freed)
{
unsigned i;
for (i = 0; i < num_to_be_freed; i++) {
zone_free(zone, to_be_freed[i]);
to_be_freed[i] = NULL;
}
}
static size_t
zone_pressure_relief(struct _malloc_zone_t *zone, size_t goal)
{
return 0;
} }
static size_t static size_t
@@ -152,6 +261,30 @@ zone_good_size(malloc_zone_t *zone, size_t size)
return (s2u(size)); return (s2u(size));
} }
static kern_return_t
zone_enumerator(task_t task, void *data, unsigned type_mask,
vm_address_t zone_address, memory_reader_t reader,
vm_range_recorder_t recorder)
{
return KERN_SUCCESS;
}
static boolean_t
zone_check(malloc_zone_t *zone)
{
return true;
}
static void
zone_print(malloc_zone_t *zone, boolean_t verbose)
{
}
static void
zone_log(malloc_zone_t *zone, void *address)
{
}
static void static void
zone_force_lock(malloc_zone_t *zone) zone_force_lock(malloc_zone_t *zone)
{ {
@@ -164,89 +297,119 @@ static void
zone_force_unlock(malloc_zone_t *zone) zone_force_unlock(malloc_zone_t *zone)
{ {
/*
* Call jemalloc_postfork_child() rather than
* jemalloc_postfork_parent(), because this function is executed by both
* parent and child. The parent can tolerate having state
* reinitialized, but the child cannot unlock mutexes that were locked
* by the parent.
*/
if (isthreaded) if (isthreaded)
jemalloc_postfork_parent(); jemalloc_postfork_child();
} }
JEMALLOC_ATTR(constructor) static void
void zone_statistics(malloc_zone_t *zone, malloc_statistics_t *stats)
register_zone(void) {
/* We make no effort to actually fill the values */
stats->blocks_in_use = 0;
stats->size_in_use = 0;
stats->max_size_in_use = 0;
stats->size_allocated = 0;
}
static boolean_t
zone_locked(malloc_zone_t *zone)
{
/* Pretend no lock is being held */
return false;
}
static void
zone_reinit_lock(malloc_zone_t *zone)
{
/* As of OSX 10.12, this function is only used when force_unlock would
* be used if the zone version were < 9. So just use force_unlock. */
zone_force_unlock(zone);
}
static void
zone_init(void)
{ {
jemalloc_zone.size = zone_size;
jemalloc_zone.malloc = zone_malloc;
jemalloc_zone.calloc = zone_calloc;
jemalloc_zone.valloc = zone_valloc;
jemalloc_zone.free = zone_free;
jemalloc_zone.realloc = zone_realloc;
jemalloc_zone.destroy = zone_destroy;
jemalloc_zone.zone_name = "jemalloc_zone";
jemalloc_zone.batch_malloc = zone_batch_malloc;
jemalloc_zone.batch_free = zone_batch_free;
jemalloc_zone.introspect = &jemalloc_zone_introspect;
jemalloc_zone.version = 9;
jemalloc_zone.memalign = zone_memalign;
jemalloc_zone.free_definite_size = zone_free_definite_size;
jemalloc_zone.pressure_relief = zone_pressure_relief;
jemalloc_zone_introspect.enumerator = zone_enumerator;
jemalloc_zone_introspect.good_size = zone_good_size;
jemalloc_zone_introspect.check = zone_check;
jemalloc_zone_introspect.print = zone_print;
jemalloc_zone_introspect.log = zone_log;
jemalloc_zone_introspect.force_lock = zone_force_lock;
jemalloc_zone_introspect.force_unlock = zone_force_unlock;
jemalloc_zone_introspect.statistics = zone_statistics;
jemalloc_zone_introspect.zone_locked = zone_locked;
jemalloc_zone_introspect.enable_discharge_checking = NULL;
jemalloc_zone_introspect.disable_discharge_checking = NULL;
jemalloc_zone_introspect.discharge = NULL;
#ifdef __BLOCKS__
jemalloc_zone_introspect.enumerate_discharged_pointers = NULL;
#else
jemalloc_zone_introspect.enumerate_unavailable_without_blocks = NULL;
#endif
jemalloc_zone_introspect.reinit_lock = zone_reinit_lock;
}
static malloc_zone_t *
zone_default_get(void)
{
malloc_zone_t **zones = NULL;
unsigned int num_zones = 0;
/* /*
* If something else replaced the system default zone allocator, don't * On OSX 10.12, malloc_default_zone returns a special zone that is not
* register jemalloc's. * present in the list of registered zones. That zone uses a "lite zone"
* if one is present (apparently enabled when malloc stack logging is
* enabled), or the first registered zone otherwise. In practice this
* means unless malloc stack logging is enabled, the first registered
* zone is the default. So get the list of zones to get the first one,
* instead of relying on malloc_default_zone.
*/ */
malloc_zone_t *default_zone = malloc_default_zone(); if (KERN_SUCCESS != malloc_get_all_zones(0, NULL,
malloc_zone_t *purgeable_zone = NULL; (vm_address_t**)&zones, &num_zones)) {
if (!default_zone->zone_name || /*
strcmp(default_zone->zone_name, "DefaultMallocZone") != 0) { * Reset the value in case the failure happened after it was
return; * set.
*/
num_zones = 0;
} }
zone.size = (void *)zone_size; if (num_zones)
zone.malloc = (void *)zone_malloc; return (zones[0]);
zone.calloc = (void *)zone_calloc;
zone.valloc = (void *)zone_valloc;
zone.free = (void *)zone_free;
zone.realloc = (void *)zone_realloc;
zone.destroy = (void *)zone_destroy;
zone.zone_name = "jemalloc_zone";
zone.batch_malloc = NULL;
zone.batch_free = NULL;
zone.introspect = &zone_introspect;
zone.version = JEMALLOC_ZONE_VERSION;
#if (JEMALLOC_ZONE_VERSION >= 5)
zone.memalign = zone_memalign;
#endif
#if (JEMALLOC_ZONE_VERSION >= 6)
zone.free_definite_size = zone_free_definite_size;
#endif
#if (JEMALLOC_ZONE_VERSION >= 8)
zone.pressure_relief = NULL;
#endif
zone_introspect.enumerator = NULL; return (malloc_default_zone());
zone_introspect.good_size = (void *)zone_good_size; }
zone_introspect.check = NULL;
zone_introspect.print = NULL;
zone_introspect.log = NULL;
zone_introspect.force_lock = (void *)zone_force_lock;
zone_introspect.force_unlock = (void *)zone_force_unlock;
zone_introspect.statistics = NULL;
#if (JEMALLOC_ZONE_VERSION >= 6)
zone_introspect.zone_locked = NULL;
#endif
#if (JEMALLOC_ZONE_VERSION >= 7)
zone_introspect.enable_discharge_checking = NULL;
zone_introspect.disable_discharge_checking = NULL;
zone_introspect.discharge = NULL;
#ifdef __BLOCKS__
zone_introspect.enumerate_discharged_pointers = NULL;
#else
zone_introspect.enumerate_unavailable_without_blocks = NULL;
#endif
#endif
/* /* As written, this function can only promote jemalloc_zone. */
* The default purgeable zone is created lazily by OSX's libc. It uses static void
* the default zone when it is created for "small" allocations zone_promote(void)
* (< 15 KiB), but assumes the default zone is a scalable_zone. This {
* obviously fails when the default zone is the jemalloc zone, so malloc_zone_t *zone;
* malloc_default_purgeable_zone is called beforehand so that the
* default purgeable zone is created when the default zone is still
* a scalable_zone. As purgeable zones only exist on >= 10.6, we need
* to check for the existence of malloc_default_purgeable_zone() at
* run time.
*/
if (malloc_default_purgeable_zone != NULL)
purgeable_zone = malloc_default_purgeable_zone();
/* Register the custom zone. At this point it won't be the default. */
malloc_zone_register(&zone);
do { do {
default_zone = malloc_default_zone();
/* /*
* Unregister and reregister the default zone. On OSX >= 10.6, * Unregister and reregister the default zone. On OSX >= 10.6,
* unregistering takes the last registered zone and places it * unregistering takes the last registered zone and places it
@@ -257,6 +420,7 @@ register_zone(void)
*/ */
malloc_zone_unregister(default_zone); malloc_zone_unregister(default_zone);
malloc_zone_register(default_zone); malloc_zone_register(default_zone);
/* /*
* On OSX 10.6, having the default purgeable zone appear before * On OSX 10.6, having the default purgeable zone appear before
* the default zone makes some things crash because it thinks it * the default zone makes some things crash because it thinks it
@@ -268,9 +432,47 @@ register_zone(void)
* above, i.e. the default zone. Registering it again then puts * above, i.e. the default zone. Registering it again then puts
* it at the end, obviously after the default zone. * it at the end, obviously after the default zone.
*/ */
if (purgeable_zone) { if (purgeable_zone != NULL) {
malloc_zone_unregister(purgeable_zone); malloc_zone_unregister(purgeable_zone);
malloc_zone_register(purgeable_zone); malloc_zone_register(purgeable_zone);
} }
} while (malloc_default_zone() != &zone);
zone = zone_default_get();
} while (zone != &jemalloc_zone);
}
JEMALLOC_ATTR(constructor)
void
zone_register(void)
{
/*
* If something else replaced the system default zone allocator, don't
* register jemalloc's.
*/
default_zone = zone_default_get();
if (!default_zone->zone_name || strcmp(default_zone->zone_name,
"DefaultMallocZone") != 0)
return;
/*
* The default purgeable zone is created lazily by OSX's libc. It uses
* the default zone when it is created for "small" allocations
* (< 15 KiB), but assumes the default zone is a scalable_zone. This
* obviously fails when the default zone is the jemalloc zone, so
* malloc_default_purgeable_zone() is called beforehand so that the
* default purgeable zone is created when the default zone is still
* a scalable_zone. As purgeable zones only exist on >= 10.6, we need
* to check for the existence of malloc_default_purgeable_zone() at
* run time.
*/
purgeable_zone = (malloc_default_purgeable_zone == NULL) ? NULL :
malloc_default_purgeable_zone();
/* Register the custom zone. At this point it won't be the default. */
zone_init();
malloc_zone_register(&jemalloc_zone);
/* Promote the custom zone to be default. */
zone_promote();
} }

View File

@@ -8,6 +8,8 @@
typedef struct { typedef struct {
#ifdef _WIN32 #ifdef _WIN32
CRITICAL_SECTION lock; CRITICAL_SECTION lock;
#elif (defined(JEMALLOC_OS_UNFAIR_LOCK))
os_unfair_lock lock;
#elif (defined(JEMALLOC_OSSPIN)) #elif (defined(JEMALLOC_OSSPIN))
OSSpinLock lock; OSSpinLock lock;
#else #else

View File

@@ -19,8 +19,8 @@ thd_start(void *arg)
size_t sz; size_t sz;
sz = sizeof(arena_ind); sz = sizeof(arena_ind);
assert_d_eq(mallctl("arenas.extend", &arena_ind, &sz, NULL, 0), 0, assert_d_eq(mallctl("arenas.extend", (void *)&arena_ind, &sz, NULL, 0),
"Error in arenas.extend"); 0, "Error in arenas.extend");
if (thread_ind % 4 != 3) { if (thread_ind % 4 != 3) {
size_t mib[3]; size_t mib[3];

View File

@@ -1,9 +1,20 @@
#include "test/jemalloc_test.h" #include "test/jemalloc_test.h"
#define CHUNK 0x400000 #define CHUNK 0x400000
/* #define MAXALIGN ((size_t)UINT64_C(0x80000000000)) */ #define MAXALIGN (((size_t)1) << 23)
#define MAXALIGN ((size_t)0x2000000LU)
#define NITER 4 /*
* On systems which can't merge extents, tests that call this function generate
* a lot of dirty memory very quickly. Purging between cycles mitigates
* potential OOM on e.g. 32-bit Windows.
*/
static void
purge(void)
{
assert_d_eq(mallctl("arena.0.purge", NULL, NULL, NULL, 0), 0,
"Unexpected mallctl error");
}
TEST_BEGIN(test_alignment_errors) TEST_BEGIN(test_alignment_errors)
{ {
@@ -74,6 +85,7 @@ TEST_END
TEST_BEGIN(test_alignment_and_size) TEST_BEGIN(test_alignment_and_size)
{ {
#define NITER 4
size_t alignment, size, total; size_t alignment, size, total;
unsigned i; unsigned i;
void *ps[NITER]; void *ps[NITER];
@@ -110,7 +122,9 @@ TEST_BEGIN(test_alignment_and_size)
} }
} }
} }
purge();
} }
#undef NITER
} }
TEST_END TEST_END

View File

@@ -18,14 +18,14 @@ thd_start(void *arg)
size_t sz, usize; size_t sz, usize;
sz = sizeof(a0); sz = sizeof(a0);
if ((err = mallctl("thread.allocated", &a0, &sz, NULL, 0))) { if ((err = mallctl("thread.allocated", (void *)&a0, &sz, NULL, 0))) {
if (err == ENOENT) if (err == ENOENT)
goto label_ENOENT; goto label_ENOENT;
test_fail("%s(): Error in mallctl(): %s", __func__, test_fail("%s(): Error in mallctl(): %s", __func__,
strerror(err)); strerror(err));
} }
sz = sizeof(ap0); sz = sizeof(ap0);
if ((err = mallctl("thread.allocatedp", &ap0, &sz, NULL, 0))) { if ((err = mallctl("thread.allocatedp", (void *)&ap0, &sz, NULL, 0))) {
if (err == ENOENT) if (err == ENOENT)
goto label_ENOENT; goto label_ENOENT;
test_fail("%s(): Error in mallctl(): %s", __func__, test_fail("%s(): Error in mallctl(): %s", __func__,
@@ -36,14 +36,15 @@ thd_start(void *arg)
"storage"); "storage");
sz = sizeof(d0); sz = sizeof(d0);
if ((err = mallctl("thread.deallocated", &d0, &sz, NULL, 0))) { if ((err = mallctl("thread.deallocated", (void *)&d0, &sz, NULL, 0))) {
if (err == ENOENT) if (err == ENOENT)
goto label_ENOENT; goto label_ENOENT;
test_fail("%s(): Error in mallctl(): %s", __func__, test_fail("%s(): Error in mallctl(): %s", __func__,
strerror(err)); strerror(err));
} }
sz = sizeof(dp0); sz = sizeof(dp0);
if ((err = mallctl("thread.deallocatedp", &dp0, &sz, NULL, 0))) { if ((err = mallctl("thread.deallocatedp", (void *)&dp0, &sz, NULL,
0))) {
if (err == ENOENT) if (err == ENOENT)
goto label_ENOENT; goto label_ENOENT;
test_fail("%s(): Error in mallctl(): %s", __func__, test_fail("%s(): Error in mallctl(): %s", __func__,
@@ -57,9 +58,9 @@ thd_start(void *arg)
assert_ptr_not_null(p, "Unexpected malloc() error"); assert_ptr_not_null(p, "Unexpected malloc() error");
sz = sizeof(a1); sz = sizeof(a1);
mallctl("thread.allocated", &a1, &sz, NULL, 0); mallctl("thread.allocated", (void *)&a1, &sz, NULL, 0);
sz = sizeof(ap1); sz = sizeof(ap1);
mallctl("thread.allocatedp", &ap1, &sz, NULL, 0); mallctl("thread.allocatedp", (void *)&ap1, &sz, NULL, 0);
assert_u64_eq(*ap1, a1, assert_u64_eq(*ap1, a1,
"Dereferenced \"thread.allocatedp\" value should equal " "Dereferenced \"thread.allocatedp\" value should equal "
"\"thread.allocated\" value"); "\"thread.allocated\" value");
@@ -74,9 +75,9 @@ thd_start(void *arg)
free(p); free(p);
sz = sizeof(d1); sz = sizeof(d1);
mallctl("thread.deallocated", &d1, &sz, NULL, 0); mallctl("thread.deallocated", (void *)&d1, &sz, NULL, 0);
sz = sizeof(dp1); sz = sizeof(dp1);
mallctl("thread.deallocatedp", &dp1, &sz, NULL, 0); mallctl("thread.deallocatedp", (void *)&dp1, &sz, NULL, 0);
assert_u64_eq(*dp1, d1, assert_u64_eq(*dp1, d1,
"Dereferenced \"thread.deallocatedp\" value should equal " "Dereferenced \"thread.deallocatedp\" value should equal "
"\"thread.deallocated\" value"); "\"thread.deallocated\" value");

View File

@@ -1,9 +1,5 @@
#include "test/jemalloc_test.h" #include "test/jemalloc_test.h"
#ifdef JEMALLOC_FILL
const char *malloc_conf = "junk:false";
#endif
static chunk_hooks_t orig_hooks; static chunk_hooks_t orig_hooks;
static chunk_hooks_t old_hooks; static chunk_hooks_t old_hooks;
@@ -137,8 +133,8 @@ TEST_BEGIN(test_chunk)
bool xallocx_success_a, xallocx_success_b, xallocx_success_c; bool xallocx_success_a, xallocx_success_b, xallocx_success_c;
sz = sizeof(unsigned); sz = sizeof(unsigned);
assert_d_eq(mallctl("arenas.extend", &arena_ind, &sz, NULL, 0), 0, assert_d_eq(mallctl("arenas.extend", (void *)&arena_ind, &sz, NULL, 0),
"Unexpected mallctl() failure"); 0, "Unexpected mallctl() failure");
flags = MALLOCX_ARENA(arena_ind) | MALLOCX_TCACHE_NONE; flags = MALLOCX_ARENA(arena_ind) | MALLOCX_TCACHE_NONE;
/* Install custom chunk hooks. */ /* Install custom chunk hooks. */
@@ -148,8 +144,9 @@ TEST_BEGIN(test_chunk)
hooks_mib[1] = (size_t)arena_ind; hooks_mib[1] = (size_t)arena_ind;
old_size = sizeof(chunk_hooks_t); old_size = sizeof(chunk_hooks_t);
new_size = sizeof(chunk_hooks_t); new_size = sizeof(chunk_hooks_t);
assert_d_eq(mallctlbymib(hooks_mib, hooks_miblen, &old_hooks, &old_size, assert_d_eq(mallctlbymib(hooks_mib, hooks_miblen, (void *)&old_hooks,
&new_hooks, new_size), 0, "Unexpected chunk_hooks error"); &old_size, (void *)&new_hooks, new_size), 0,
"Unexpected chunk_hooks error");
orig_hooks = old_hooks; orig_hooks = old_hooks;
assert_ptr_ne(old_hooks.alloc, chunk_alloc, "Unexpected alloc error"); assert_ptr_ne(old_hooks.alloc, chunk_alloc, "Unexpected alloc error");
assert_ptr_ne(old_hooks.dalloc, chunk_dalloc, assert_ptr_ne(old_hooks.dalloc, chunk_dalloc,
@@ -164,18 +161,18 @@ TEST_BEGIN(test_chunk)
/* Get large size classes. */ /* Get large size classes. */
sz = sizeof(size_t); sz = sizeof(size_t);
assert_d_eq(mallctl("arenas.lrun.0.size", &large0, &sz, NULL, 0), 0, assert_d_eq(mallctl("arenas.lrun.0.size", (void *)&large0, &sz, NULL,
"Unexpected arenas.lrun.0.size failure"); 0), 0, "Unexpected arenas.lrun.0.size failure");
assert_d_eq(mallctl("arenas.lrun.1.size", &large1, &sz, NULL, 0), 0, assert_d_eq(mallctl("arenas.lrun.1.size", (void *)&large1, &sz, NULL,
"Unexpected arenas.lrun.1.size failure"); 0), 0, "Unexpected arenas.lrun.1.size failure");
/* Get huge size classes. */ /* Get huge size classes. */
assert_d_eq(mallctl("arenas.hchunk.0.size", &huge0, &sz, NULL, 0), 0, assert_d_eq(mallctl("arenas.hchunk.0.size", (void *)&huge0, &sz, NULL,
"Unexpected arenas.hchunk.0.size failure"); 0), 0, "Unexpected arenas.hchunk.0.size failure");
assert_d_eq(mallctl("arenas.hchunk.1.size", &huge1, &sz, NULL, 0), 0, assert_d_eq(mallctl("arenas.hchunk.1.size", (void *)&huge1, &sz, NULL,
"Unexpected arenas.hchunk.1.size failure"); 0), 0, "Unexpected arenas.hchunk.1.size failure");
assert_d_eq(mallctl("arenas.hchunk.2.size", &huge2, &sz, NULL, 0), 0, assert_d_eq(mallctl("arenas.hchunk.2.size", (void *)&huge2, &sz, NULL,
"Unexpected arenas.hchunk.2.size failure"); 0), 0, "Unexpected arenas.hchunk.2.size failure");
/* Test dalloc/decommit/purge cascade. */ /* Test dalloc/decommit/purge cascade. */
purge_miblen = sizeof(purge_mib)/sizeof(size_t); purge_miblen = sizeof(purge_mib)/sizeof(size_t);
@@ -265,9 +262,9 @@ TEST_BEGIN(test_chunk)
/* Restore chunk hooks. */ /* Restore chunk hooks. */
assert_d_eq(mallctlbymib(hooks_mib, hooks_miblen, NULL, NULL, assert_d_eq(mallctlbymib(hooks_mib, hooks_miblen, NULL, NULL,
&old_hooks, new_size), 0, "Unexpected chunk_hooks error"); (void *)&old_hooks, new_size), 0, "Unexpected chunk_hooks error");
assert_d_eq(mallctlbymib(hooks_mib, hooks_miblen, &old_hooks, &old_size, assert_d_eq(mallctlbymib(hooks_mib, hooks_miblen, (void *)&old_hooks,
NULL, 0), 0, "Unexpected chunk_hooks error"); &old_size, NULL, 0), 0, "Unexpected chunk_hooks error");
assert_ptr_eq(old_hooks.alloc, orig_hooks.alloc, assert_ptr_eq(old_hooks.alloc, orig_hooks.alloc,
"Unexpected alloc error"); "Unexpected alloc error");
assert_ptr_eq(old_hooks.dalloc, orig_hooks.dalloc, assert_ptr_eq(old_hooks.dalloc, orig_hooks.dalloc,

View File

@@ -0,0 +1,5 @@
#!/bin/sh
if [ "x${enable_fill}" = "x1" ] ; then
export MALLOC_CONF="junk:false"
fi

View File

@@ -1,9 +1,5 @@
#include "test/jemalloc_test.h" #include "test/jemalloc_test.h"
#ifdef JEMALLOC_FILL
const char *malloc_conf = "junk:false";
#endif
static unsigned static unsigned
get_nsizes_impl(const char *cmd) get_nsizes_impl(const char *cmd)
{ {
@@ -11,7 +7,7 @@ get_nsizes_impl(const char *cmd)
size_t z; size_t z;
z = sizeof(unsigned); z = sizeof(unsigned);
assert_d_eq(mallctl(cmd, &ret, &z, NULL, 0), 0, assert_d_eq(mallctl(cmd, (void *)&ret, &z, NULL, 0), 0,
"Unexpected mallctl(\"%s\", ...) failure", cmd); "Unexpected mallctl(\"%s\", ...) failure", cmd);
return (ret); return (ret);
@@ -37,7 +33,7 @@ get_size_impl(const char *cmd, size_t ind)
0, "Unexpected mallctlnametomib(\"%s\", ...) failure", cmd); 0, "Unexpected mallctlnametomib(\"%s\", ...) failure", cmd);
mib[2] = ind; mib[2] = ind;
z = sizeof(size_t); z = sizeof(size_t);
assert_d_eq(mallctlbymib(mib, miblen, &ret, &z, NULL, 0), assert_d_eq(mallctlbymib(mib, miblen, (void *)&ret, &z, NULL, 0),
0, "Unexpected mallctlbymib([\"%s\", %zu], ...) failure", cmd, ind); 0, "Unexpected mallctlbymib([\"%s\", %zu], ...) failure", cmd, ind);
return (ret); return (ret);
@@ -50,6 +46,19 @@ get_huge_size(size_t ind)
return (get_size_impl("arenas.hchunk.0.size", ind)); return (get_size_impl("arenas.hchunk.0.size", ind));
} }
/*
* On systems which can't merge extents, tests that call this function generate
* a lot of dirty memory very quickly. Purging between cycles mitigates
* potential OOM on e.g. 32-bit Windows.
*/
static void
purge(void)
{
assert_d_eq(mallctl("arena.0.purge", NULL, NULL, NULL, 0), 0,
"Unexpected mallctl error");
}
TEST_BEGIN(test_overflow) TEST_BEGIN(test_overflow)
{ {
size_t hugemax; size_t hugemax;
@@ -96,6 +105,7 @@ TEST_BEGIN(test_oom)
if (ptrs[i] != NULL) if (ptrs[i] != NULL)
dallocx(ptrs[i], 0); dallocx(ptrs[i], 0);
} }
purge();
#if LG_SIZEOF_PTR == 3 #if LG_SIZEOF_PTR == 3
assert_ptr_null(mallocx(0x8000000000000000ULL, assert_ptr_null(mallocx(0x8000000000000000ULL,
@@ -113,7 +123,7 @@ TEST_END
TEST_BEGIN(test_basic) TEST_BEGIN(test_basic)
{ {
#define MAXSZ (((size_t)1) << 26) #define MAXSZ (((size_t)1) << 23)
size_t sz; size_t sz;
for (sz = 1; sz < MAXSZ; sz = nallocx(sz, 0) + 1) { for (sz = 1; sz < MAXSZ; sz = nallocx(sz, 0) + 1) {
@@ -122,23 +132,28 @@ TEST_BEGIN(test_basic)
nsz = nallocx(sz, 0); nsz = nallocx(sz, 0);
assert_zu_ne(nsz, 0, "Unexpected nallocx() error"); assert_zu_ne(nsz, 0, "Unexpected nallocx() error");
p = mallocx(sz, 0); p = mallocx(sz, 0);
assert_ptr_not_null(p, "Unexpected mallocx() error"); assert_ptr_not_null(p,
"Unexpected mallocx(size=%zx, flags=0) error", sz);
rsz = sallocx(p, 0); rsz = sallocx(p, 0);
assert_zu_ge(rsz, sz, "Real size smaller than expected"); assert_zu_ge(rsz, sz, "Real size smaller than expected");
assert_zu_eq(nsz, rsz, "nallocx()/sallocx() size mismatch"); assert_zu_eq(nsz, rsz, "nallocx()/sallocx() size mismatch");
dallocx(p, 0); dallocx(p, 0);
p = mallocx(sz, 0); p = mallocx(sz, 0);
assert_ptr_not_null(p, "Unexpected mallocx() error"); assert_ptr_not_null(p,
"Unexpected mallocx(size=%zx, flags=0) error", sz);
dallocx(p, 0); dallocx(p, 0);
nsz = nallocx(sz, MALLOCX_ZERO); nsz = nallocx(sz, MALLOCX_ZERO);
assert_zu_ne(nsz, 0, "Unexpected nallocx() error"); assert_zu_ne(nsz, 0, "Unexpected nallocx() error");
p = mallocx(sz, MALLOCX_ZERO); p = mallocx(sz, MALLOCX_ZERO);
assert_ptr_not_null(p, "Unexpected mallocx() error"); assert_ptr_not_null(p,
"Unexpected mallocx(size=%zx, flags=MALLOCX_ZERO) error",
nsz);
rsz = sallocx(p, 0); rsz = sallocx(p, 0);
assert_zu_eq(nsz, rsz, "nallocx()/sallocx() rsize mismatch"); assert_zu_eq(nsz, rsz, "nallocx()/sallocx() rsize mismatch");
dallocx(p, 0); dallocx(p, 0);
purge();
} }
#undef MAXSZ #undef MAXSZ
} }
@@ -146,7 +161,7 @@ TEST_END
TEST_BEGIN(test_alignment_and_size) TEST_BEGIN(test_alignment_and_size)
{ {
#define MAXALIGN (((size_t)1) << 25) #define MAXALIGN (((size_t)1) << 23)
#define NITER 4 #define NITER 4
size_t nsz, rsz, sz, alignment, total; size_t nsz, rsz, sz, alignment, total;
unsigned i; unsigned i;
@@ -196,6 +211,7 @@ TEST_BEGIN(test_alignment_and_size)
} }
} }
} }
purge();
} }
#undef MAXALIGN #undef MAXALIGN
#undef NITER #undef NITER

View File

@@ -0,0 +1,5 @@
#!/bin/sh
if [ "x${enable_fill}" = "x1" ] ; then
export MALLOC_CONF="junk:false"
fi

View File

@@ -8,8 +8,8 @@ TEST_BEGIN(test_overflow)
void *p; void *p;
sz = sizeof(unsigned); sz = sizeof(unsigned);
assert_d_eq(mallctl("arenas.nhchunks", &nhchunks, &sz, NULL, 0), 0, assert_d_eq(mallctl("arenas.nhchunks", (void *)&nhchunks, &sz, NULL, 0),
"Unexpected mallctl() error"); 0, "Unexpected mallctl() error");
miblen = sizeof(mib) / sizeof(size_t); miblen = sizeof(mib) / sizeof(size_t);
assert_d_eq(mallctlnametomib("arenas.hchunk.0.size", mib, &miblen), 0, assert_d_eq(mallctlnametomib("arenas.hchunk.0.size", mib, &miblen), 0,
@@ -17,8 +17,8 @@ TEST_BEGIN(test_overflow)
mib[2] = nhchunks - 1; mib[2] = nhchunks - 1;
sz = sizeof(size_t); sz = sizeof(size_t);
assert_d_eq(mallctlbymib(mib, miblen, &max_size_class, &sz, NULL, 0), 0, assert_d_eq(mallctlbymib(mib, miblen, (void *)&max_size_class, &sz,
"Unexpected mallctlbymib() error"); NULL, 0), 0, "Unexpected mallctlbymib() error");
assert_ptr_null(malloc(max_size_class + 1), assert_ptr_null(malloc(max_size_class + 1),
"Expected OOM due to over-sized allocation request"); "Expected OOM due to over-sized allocation request");

View File

@@ -1,9 +1,20 @@
#include "test/jemalloc_test.h" #include "test/jemalloc_test.h"
#define CHUNK 0x400000 #define CHUNK 0x400000
/* #define MAXALIGN ((size_t)UINT64_C(0x80000000000)) */ #define MAXALIGN (((size_t)1) << 23)
#define MAXALIGN ((size_t)0x2000000LU)
#define NITER 4 /*
* On systems which can't merge extents, tests that call this function generate
* a lot of dirty memory very quickly. Purging between cycles mitigates
* potential OOM on e.g. 32-bit Windows.
*/
static void
purge(void)
{
assert_d_eq(mallctl("arena.0.purge", NULL, NULL, NULL, 0), 0,
"Unexpected mallctl error");
}
TEST_BEGIN(test_alignment_errors) TEST_BEGIN(test_alignment_errors)
{ {
@@ -66,6 +77,7 @@ TEST_END
TEST_BEGIN(test_alignment_and_size) TEST_BEGIN(test_alignment_and_size)
{ {
#define NITER 4
size_t alignment, size, total; size_t alignment, size, total;
unsigned i; unsigned i;
int err; int err;
@@ -104,7 +116,9 @@ TEST_BEGIN(test_alignment_and_size)
} }
} }
} }
purge();
} }
#undef NITER
} }
TEST_END TEST_END

View File

@@ -7,7 +7,7 @@ get_nsizes_impl(const char *cmd)
size_t z; size_t z;
z = sizeof(unsigned); z = sizeof(unsigned);
assert_d_eq(mallctl(cmd, &ret, &z, NULL, 0), 0, assert_d_eq(mallctl(cmd, (void *)&ret, &z, NULL, 0), 0,
"Unexpected mallctl(\"%s\", ...) failure", cmd); "Unexpected mallctl(\"%s\", ...) failure", cmd);
return (ret); return (ret);
@@ -33,7 +33,7 @@ get_size_impl(const char *cmd, size_t ind)
0, "Unexpected mallctlnametomib(\"%s\", ...) failure", cmd); 0, "Unexpected mallctlnametomib(\"%s\", ...) failure", cmd);
mib[2] = ind; mib[2] = ind;
z = sizeof(size_t); z = sizeof(size_t);
assert_d_eq(mallctlbymib(mib, miblen, &ret, &z, NULL, 0), assert_d_eq(mallctlbymib(mib, miblen, (void *)&ret, &z, NULL, 0),
0, "Unexpected mallctlbymib([\"%s\", %zu], ...) failure", cmd, ind); 0, "Unexpected mallctlbymib([\"%s\", %zu], ...) failure", cmd, ind);
return (ret); return (ret);

View File

@@ -1,7 +1,7 @@
#include "test/jemalloc_test.h" #include "test/jemalloc_test.h"
#define MAXALIGN (((size_t)1) << 25) #define MAXALIGN (((size_t)1) << 22)
#define NITER 4 #define NITER 3
TEST_BEGIN(test_basic) TEST_BEGIN(test_basic)
{ {

View File

@@ -16,8 +16,8 @@ thd_start(void *arg)
free(p); free(p);
size = sizeof(arena_ind); size = sizeof(arena_ind);
if ((err = mallctl("thread.arena", &arena_ind, &size, &main_arena_ind, if ((err = mallctl("thread.arena", (void *)&arena_ind, &size,
sizeof(main_arena_ind)))) { (void *)&main_arena_ind, sizeof(main_arena_ind)))) {
char buf[BUFERROR_BUF]; char buf[BUFERROR_BUF];
buferror(err, buf, sizeof(buf)); buferror(err, buf, sizeof(buf));
@@ -25,7 +25,8 @@ thd_start(void *arg)
} }
size = sizeof(arena_ind); size = sizeof(arena_ind);
if ((err = mallctl("thread.arena", &arena_ind, &size, NULL, 0))) { if ((err = mallctl("thread.arena", (void *)&arena_ind, &size, NULL,
0))) {
char buf[BUFERROR_BUF]; char buf[BUFERROR_BUF];
buferror(err, buf, sizeof(buf)); buferror(err, buf, sizeof(buf));
@@ -50,7 +51,8 @@ TEST_BEGIN(test_thread_arena)
assert_ptr_not_null(p, "Error in malloc()"); assert_ptr_not_null(p, "Error in malloc()");
size = sizeof(arena_ind); size = sizeof(arena_ind);
if ((err = mallctl("thread.arena", &arena_ind, &size, NULL, 0))) { if ((err = mallctl("thread.arena", (void *)&arena_ind, &size, NULL,
0))) {
char buf[BUFERROR_BUF]; char buf[BUFERROR_BUF];
buferror(err, buf, sizeof(buf)); buferror(err, buf, sizeof(buf));

View File

@@ -16,7 +16,8 @@ thd_start(void *arg)
bool e0, e1; bool e0, e1;
sz = sizeof(bool); sz = sizeof(bool);
if ((err = mallctl("thread.tcache.enabled", &e0, &sz, NULL, 0))) { if ((err = mallctl("thread.tcache.enabled", (void *)&e0, &sz, NULL,
0))) {
if (err == ENOENT) { if (err == ENOENT) {
assert_false(config_tcache, assert_false(config_tcache,
"ENOENT should only be returned if tcache is " "ENOENT should only be returned if tcache is "
@@ -27,53 +28,53 @@ thd_start(void *arg)
if (e0) { if (e0) {
e1 = false; e1 = false;
assert_d_eq(mallctl("thread.tcache.enabled", &e0, &sz, &e1, sz), assert_d_eq(mallctl("thread.tcache.enabled", (void *)&e0, &sz,
0, "Unexpected mallctl() error"); (void *)&e1, sz), 0, "Unexpected mallctl() error");
assert_true(e0, "tcache should be enabled"); assert_true(e0, "tcache should be enabled");
} }
e1 = true; e1 = true;
assert_d_eq(mallctl("thread.tcache.enabled", &e0, &sz, &e1, sz), 0, assert_d_eq(mallctl("thread.tcache.enabled", (void *)&e0, &sz,
"Unexpected mallctl() error"); (void *)&e1, sz), 0, "Unexpected mallctl() error");
assert_false(e0, "tcache should be disabled"); assert_false(e0, "tcache should be disabled");
e1 = true; e1 = true;
assert_d_eq(mallctl("thread.tcache.enabled", &e0, &sz, &e1, sz), 0, assert_d_eq(mallctl("thread.tcache.enabled", (void *)&e0, &sz,
"Unexpected mallctl() error"); (void *)&e1, sz), 0, "Unexpected mallctl() error");
assert_true(e0, "tcache should be enabled"); assert_true(e0, "tcache should be enabled");
e1 = false; e1 = false;
assert_d_eq(mallctl("thread.tcache.enabled", &e0, &sz, &e1, sz), 0, assert_d_eq(mallctl("thread.tcache.enabled", (void *)&e0, &sz,
"Unexpected mallctl() error"); (void *)&e1, sz), 0, "Unexpected mallctl() error");
assert_true(e0, "tcache should be enabled"); assert_true(e0, "tcache should be enabled");
e1 = false; e1 = false;
assert_d_eq(mallctl("thread.tcache.enabled", &e0, &sz, &e1, sz), 0, assert_d_eq(mallctl("thread.tcache.enabled", (void *)&e0, &sz,
"Unexpected mallctl() error"); (void *)&e1, sz), 0, "Unexpected mallctl() error");
assert_false(e0, "tcache should be disabled"); assert_false(e0, "tcache should be disabled");
free(malloc(1)); free(malloc(1));
e1 = true; e1 = true;
assert_d_eq(mallctl("thread.tcache.enabled", &e0, &sz, &e1, sz), 0, assert_d_eq(mallctl("thread.tcache.enabled", (void *)&e0, &sz,
"Unexpected mallctl() error"); (void *)&e1, sz), 0, "Unexpected mallctl() error");
assert_false(e0, "tcache should be disabled"); assert_false(e0, "tcache should be disabled");
free(malloc(1)); free(malloc(1));
e1 = true; e1 = true;
assert_d_eq(mallctl("thread.tcache.enabled", &e0, &sz, &e1, sz), 0, assert_d_eq(mallctl("thread.tcache.enabled", (void *)&e0, &sz,
"Unexpected mallctl() error"); (void *)&e1, sz), 0, "Unexpected mallctl() error");
assert_true(e0, "tcache should be enabled"); assert_true(e0, "tcache should be enabled");
free(malloc(1)); free(malloc(1));
e1 = false; e1 = false;
assert_d_eq(mallctl("thread.tcache.enabled", &e0, &sz, &e1, sz), 0, assert_d_eq(mallctl("thread.tcache.enabled", (void *)&e0, &sz,
"Unexpected mallctl() error"); (void *)&e1, sz), 0, "Unexpected mallctl() error");
assert_true(e0, "tcache should be enabled"); assert_true(e0, "tcache should be enabled");
free(malloc(1)); free(malloc(1));
e1 = false; e1 = false;
assert_d_eq(mallctl("thread.tcache.enabled", &e0, &sz, &e1, sz), 0, assert_d_eq(mallctl("thread.tcache.enabled", (void *)&e0, &sz,
"Unexpected mallctl() error"); (void *)&e1, sz), 0, "Unexpected mallctl() error");
assert_false(e0, "tcache should be disabled"); assert_false(e0, "tcache should be disabled");
free(malloc(1)); free(malloc(1));

View File

@@ -1,9 +1,5 @@
#include "test/jemalloc_test.h" #include "test/jemalloc_test.h"
#ifdef JEMALLOC_FILL
const char *malloc_conf = "junk:false";
#endif
/* /*
* Use a separate arena for xallocx() extension/contraction tests so that * Use a separate arena for xallocx() extension/contraction tests so that
* internal allocation e.g. by heap profiling can't interpose allocations where * internal allocation e.g. by heap profiling can't interpose allocations where
@@ -16,8 +12,8 @@ arena_ind(void)
if (ind == 0) { if (ind == 0) {
size_t sz = sizeof(ind); size_t sz = sizeof(ind);
assert_d_eq(mallctl("arenas.extend", &ind, &sz, NULL, 0), 0, assert_d_eq(mallctl("arenas.extend", (void *)&ind, &sz, NULL,
"Unexpected mallctl failure creating arena"); 0), 0, "Unexpected mallctl failure creating arena");
} }
return (ind); return (ind);
@@ -78,7 +74,7 @@ get_nsizes_impl(const char *cmd)
size_t z; size_t z;
z = sizeof(unsigned); z = sizeof(unsigned);
assert_d_eq(mallctl(cmd, &ret, &z, NULL, 0), 0, assert_d_eq(mallctl(cmd, (void *)&ret, &z, NULL, 0), 0,
"Unexpected mallctl(\"%s\", ...) failure", cmd); "Unexpected mallctl(\"%s\", ...) failure", cmd);
return (ret); return (ret);
@@ -118,7 +114,7 @@ get_size_impl(const char *cmd, size_t ind)
0, "Unexpected mallctlnametomib(\"%s\", ...) failure", cmd); 0, "Unexpected mallctlnametomib(\"%s\", ...) failure", cmd);
mib[2] = ind; mib[2] = ind;
z = sizeof(size_t); z = sizeof(size_t);
assert_d_eq(mallctlbymib(mib, miblen, &ret, &z, NULL, 0), assert_d_eq(mallctlbymib(mib, miblen, (void *)&ret, &z, NULL, 0),
0, "Unexpected mallctlbymib([\"%s\", %zu], ...) failure", cmd, ind); 0, "Unexpected mallctlbymib([\"%s\", %zu], ...) failure", cmd, ind);
return (ret); return (ret);

View File

@@ -0,0 +1,5 @@
#!/bin/sh
if [ "x${enable_fill}" = "x1" ] ; then
export MALLOC_CONF="junk:false"
fi

View File

@@ -11,6 +11,8 @@ mtx_init(mtx_t *mtx)
#ifdef _WIN32 #ifdef _WIN32
if (!InitializeCriticalSectionAndSpinCount(&mtx->lock, _CRT_SPINCOUNT)) if (!InitializeCriticalSectionAndSpinCount(&mtx->lock, _CRT_SPINCOUNT))
return (true); return (true);
#elif (defined(JEMALLOC_OS_UNFAIR_LOCK))
mtx->lock = OS_UNFAIR_LOCK_INIT;
#elif (defined(JEMALLOC_OSSPIN)) #elif (defined(JEMALLOC_OSSPIN))
mtx->lock = 0; mtx->lock = 0;
#else #else
@@ -33,6 +35,7 @@ mtx_fini(mtx_t *mtx)
{ {
#ifdef _WIN32 #ifdef _WIN32
#elif (defined(JEMALLOC_OS_UNFAIR_LOCK))
#elif (defined(JEMALLOC_OSSPIN)) #elif (defined(JEMALLOC_OSSPIN))
#else #else
pthread_mutex_destroy(&mtx->lock); pthread_mutex_destroy(&mtx->lock);
@@ -45,6 +48,8 @@ mtx_lock(mtx_t *mtx)
#ifdef _WIN32 #ifdef _WIN32
EnterCriticalSection(&mtx->lock); EnterCriticalSection(&mtx->lock);
#elif (defined(JEMALLOC_OS_UNFAIR_LOCK))
os_unfair_lock_lock(&mtx->lock);
#elif (defined(JEMALLOC_OSSPIN)) #elif (defined(JEMALLOC_OSSPIN))
OSSpinLockLock(&mtx->lock); OSSpinLockLock(&mtx->lock);
#else #else
@@ -58,6 +63,8 @@ mtx_unlock(mtx_t *mtx)
#ifdef _WIN32 #ifdef _WIN32
LeaveCriticalSection(&mtx->lock); LeaveCriticalSection(&mtx->lock);
#elif (defined(JEMALLOC_OS_UNFAIR_LOCK))
os_unfair_lock_unlock(&mtx->lock);
#elif (defined(JEMALLOC_OSSPIN)) #elif (defined(JEMALLOC_OSSPIN))
OSSpinLockUnlock(&mtx->lock); OSSpinLockUnlock(&mtx->lock);
#else #else

View File

@@ -11,6 +11,18 @@ case @abi@ in
;; ;;
esac esac
# Make a copy of the @JEMALLOC_CPREFIX@MALLOC_CONF passed in to this script, so
# it can be repeatedly concatenated with per test settings.
export MALLOC_CONF_ALL=${@JEMALLOC_CPREFIX@MALLOC_CONF}
# Concatenate the individual test's MALLOC_CONF and MALLOC_CONF_ALL.
export_malloc_conf() {
if [ "x${MALLOC_CONF}" != "x" -a "x${MALLOC_CONF_ALL}" != "x" ] ; then
export @JEMALLOC_CPREFIX@MALLOC_CONF="${MALLOC_CONF},${MALLOC_CONF_ALL}"
else
export @JEMALLOC_CPREFIX@MALLOC_CONF="${MALLOC_CONF}${MALLOC_CONF_ALL}"
fi
}
# Corresponds to test_status_t. # Corresponds to test_status_t.
pass_code=0 pass_code=0
skip_code=1 skip_code=1
@@ -24,7 +36,22 @@ for t in $@; do
echo echo
fi fi
echo "=== ${t} ===" echo "=== ${t} ==="
${t}@exe@ @abs_srcroot@ @abs_objroot@ if [ -e "@srcroot@${t}.sh" ] ; then
# Source the shell script corresponding to the test in a subshell and
# execute the test. This allows the shell script to set MALLOC_CONF, which
# is then used to set @JEMALLOC_CPREFIX@MALLOC_CONF (thus allowing the
# per test shell script to ignore the @JEMALLOC_CPREFIX@ detail).
$(enable_fill=@enable_fill@ \
enable_prof=@enable_prof@ \
enable_tcache=@enable_tcache@ \
. @srcroot@${t}.sh && \
export_malloc_conf && \
${t}@exe@ @abs_srcroot@ @abs_objroot@)
else
$(export MALLOC_CONF= && \
export_malloc_conf &&
${t}@exe@ @abs_srcroot@ @abs_objroot@)
fi
result_code=$? result_code=$?
case ${result_code} in case ${result_code} in
${pass_code}) ${pass_code})

View File

@@ -1,9 +1,5 @@
#include "test/jemalloc_test.h" #include "test/jemalloc_test.h"
#ifdef JEMALLOC_PROF
const char *malloc_conf = "prof:true,lg_prof_sample:0";
#endif
static unsigned static unsigned
get_nsizes_impl(const char *cmd) get_nsizes_impl(const char *cmd)
{ {
@@ -11,7 +7,7 @@ get_nsizes_impl(const char *cmd)
size_t z; size_t z;
z = sizeof(unsigned); z = sizeof(unsigned);
assert_d_eq(mallctl(cmd, &ret, &z, NULL, 0), 0, assert_d_eq(mallctl(cmd, (void *)&ret, &z, NULL, 0), 0,
"Unexpected mallctl(\"%s\", ...) failure", cmd); "Unexpected mallctl(\"%s\", ...) failure", cmd);
return (ret); return (ret);
@@ -51,7 +47,7 @@ get_size_impl(const char *cmd, size_t ind)
0, "Unexpected mallctlnametomib(\"%s\", ...) failure", cmd); 0, "Unexpected mallctlnametomib(\"%s\", ...) failure", cmd);
mib[2] = ind; mib[2] = ind;
z = sizeof(size_t); z = sizeof(size_t);
assert_d_eq(mallctlbymib(mib, miblen, &ret, &z, NULL, 0), assert_d_eq(mallctlbymib(mib, miblen, (void *)&ret, &z, NULL, 0),
0, "Unexpected mallctlbymib([\"%s\", %zu], ...) failure", cmd, ind); 0, "Unexpected mallctlbymib([\"%s\", %zu], ...) failure", cmd, ind);
return (ret); return (ret);
@@ -92,8 +88,8 @@ TEST_BEGIN(test_arena_reset)
&& unlikely(opt_quarantine))); && unlikely(opt_quarantine)));
sz = sizeof(unsigned); sz = sizeof(unsigned);
assert_d_eq(mallctl("arenas.extend", &arena_ind, &sz, NULL, 0), 0, assert_d_eq(mallctl("arenas.extend", (void *)&arena_ind, &sz, NULL, 0),
"Unexpected mallctl() failure"); 0, "Unexpected mallctl() failure");
flags = MALLOCX_ARENA(arena_ind) | MALLOCX_TCACHE_NONE; flags = MALLOCX_ARENA(arena_ind) | MALLOCX_TCACHE_NONE;

5
test/unit/arena_reset.sh Normal file
View File

@@ -0,0 +1,5 @@
#!/bin/sh
if [ "x${enable_prof}" = "x1" ] ; then
export MALLOC_CONF="prof:true,lg_prof_sample:0"
fi

View File

@@ -2,24 +2,24 @@
TEST_BEGIN(test_new_delete) TEST_BEGIN(test_new_delete)
{ {
tsdn_t *tsdn; tsd_t *tsd;
ckh_t ckh; ckh_t ckh;
tsdn = tsdn_fetch(); tsd = tsd_fetch();
assert_false(ckh_new(tsdn, &ckh, 2, ckh_string_hash, assert_false(ckh_new(tsd, &ckh, 2, ckh_string_hash,
ckh_string_keycomp), "Unexpected ckh_new() error"); ckh_string_keycomp), "Unexpected ckh_new() error");
ckh_delete(tsdn, &ckh); ckh_delete(tsd, &ckh);
assert_false(ckh_new(tsdn, &ckh, 3, ckh_pointer_hash, assert_false(ckh_new(tsd, &ckh, 3, ckh_pointer_hash,
ckh_pointer_keycomp), "Unexpected ckh_new() error"); ckh_pointer_keycomp), "Unexpected ckh_new() error");
ckh_delete(tsdn, &ckh); ckh_delete(tsd, &ckh);
} }
TEST_END TEST_END
TEST_BEGIN(test_count_insert_search_remove) TEST_BEGIN(test_count_insert_search_remove)
{ {
tsdn_t *tsdn; tsd_t *tsd;
ckh_t ckh; ckh_t ckh;
const char *strs[] = { const char *strs[] = {
"a string", "a string",
@@ -30,9 +30,9 @@ TEST_BEGIN(test_count_insert_search_remove)
const char *missing = "A string not in the hash table."; const char *missing = "A string not in the hash table.";
size_t i; size_t i;
tsdn = tsdn_fetch(); tsd = tsd_fetch();
assert_false(ckh_new(tsdn, &ckh, 2, ckh_string_hash, assert_false(ckh_new(tsd, &ckh, 2, ckh_string_hash,
ckh_string_keycomp), "Unexpected ckh_new() error"); ckh_string_keycomp), "Unexpected ckh_new() error");
assert_zu_eq(ckh_count(&ckh), 0, assert_zu_eq(ckh_count(&ckh), 0,
"ckh_count() should return %zu, but it returned %zu", ZU(0), "ckh_count() should return %zu, but it returned %zu", ZU(0),
@@ -40,7 +40,7 @@ TEST_BEGIN(test_count_insert_search_remove)
/* Insert. */ /* Insert. */
for (i = 0; i < sizeof(strs)/sizeof(const char *); i++) { for (i = 0; i < sizeof(strs)/sizeof(const char *); i++) {
ckh_insert(tsdn, &ckh, strs[i], strs[i]); ckh_insert(tsd, &ckh, strs[i], strs[i]);
assert_zu_eq(ckh_count(&ckh), i+1, assert_zu_eq(ckh_count(&ckh), i+1,
"ckh_count() should return %zu, but it returned %zu", i+1, "ckh_count() should return %zu, but it returned %zu", i+1,
ckh_count(&ckh)); ckh_count(&ckh));
@@ -85,7 +85,7 @@ TEST_BEGIN(test_count_insert_search_remove)
vp = (i & 2) ? &v.p : NULL; vp = (i & 2) ? &v.p : NULL;
k.p = NULL; k.p = NULL;
v.p = NULL; v.p = NULL;
assert_false(ckh_remove(tsdn, &ckh, strs[i], kp, vp), assert_false(ckh_remove(tsd, &ckh, strs[i], kp, vp),
"Unexpected ckh_remove() error"); "Unexpected ckh_remove() error");
ks = (i & 1) ? strs[i] : (const char *)NULL; ks = (i & 1) ? strs[i] : (const char *)NULL;
@@ -101,22 +101,22 @@ TEST_BEGIN(test_count_insert_search_remove)
ckh_count(&ckh)); ckh_count(&ckh));
} }
ckh_delete(tsdn, &ckh); ckh_delete(tsd, &ckh);
} }
TEST_END TEST_END
TEST_BEGIN(test_insert_iter_remove) TEST_BEGIN(test_insert_iter_remove)
{ {
#define NITEMS ZU(1000) #define NITEMS ZU(1000)
tsdn_t *tsdn; tsd_t *tsd;
ckh_t ckh; ckh_t ckh;
void **p[NITEMS]; void **p[NITEMS];
void *q, *r; void *q, *r;
size_t i; size_t i;
tsdn = tsdn_fetch(); tsd = tsd_fetch();
assert_false(ckh_new(tsdn, &ckh, 2, ckh_pointer_hash, assert_false(ckh_new(tsd, &ckh, 2, ckh_pointer_hash,
ckh_pointer_keycomp), "Unexpected ckh_new() error"); ckh_pointer_keycomp), "Unexpected ckh_new() error");
for (i = 0; i < NITEMS; i++) { for (i = 0; i < NITEMS; i++) {
@@ -128,7 +128,7 @@ TEST_BEGIN(test_insert_iter_remove)
size_t j; size_t j;
for (j = i; j < NITEMS; j++) { for (j = i; j < NITEMS; j++) {
assert_false(ckh_insert(tsdn, &ckh, p[j], p[j]), assert_false(ckh_insert(tsd, &ckh, p[j], p[j]),
"Unexpected ckh_insert() failure"); "Unexpected ckh_insert() failure");
assert_false(ckh_search(&ckh, p[j], &q, &r), assert_false(ckh_search(&ckh, p[j], &q, &r),
"Unexpected ckh_search() failure"); "Unexpected ckh_search() failure");
@@ -143,13 +143,13 @@ TEST_BEGIN(test_insert_iter_remove)
for (j = i + 1; j < NITEMS; j++) { for (j = i + 1; j < NITEMS; j++) {
assert_false(ckh_search(&ckh, p[j], NULL, NULL), assert_false(ckh_search(&ckh, p[j], NULL, NULL),
"Unexpected ckh_search() failure"); "Unexpected ckh_search() failure");
assert_false(ckh_remove(tsdn, &ckh, p[j], &q, &r), assert_false(ckh_remove(tsd, &ckh, p[j], &q, &r),
"Unexpected ckh_remove() failure"); "Unexpected ckh_remove() failure");
assert_ptr_eq(p[j], q, "Key pointer mismatch"); assert_ptr_eq(p[j], q, "Key pointer mismatch");
assert_ptr_eq(p[j], r, "Value pointer mismatch"); assert_ptr_eq(p[j], r, "Value pointer mismatch");
assert_true(ckh_search(&ckh, p[j], NULL, NULL), assert_true(ckh_search(&ckh, p[j], NULL, NULL),
"Unexpected ckh_search() success"); "Unexpected ckh_search() success");
assert_true(ckh_remove(tsdn, &ckh, p[j], &q, &r), assert_true(ckh_remove(tsd, &ckh, p[j], &q, &r),
"Unexpected ckh_remove() success"); "Unexpected ckh_remove() success");
} }
@@ -184,13 +184,13 @@ TEST_BEGIN(test_insert_iter_remove)
for (i = 0; i < NITEMS; i++) { for (i = 0; i < NITEMS; i++) {
assert_false(ckh_search(&ckh, p[i], NULL, NULL), assert_false(ckh_search(&ckh, p[i], NULL, NULL),
"Unexpected ckh_search() failure"); "Unexpected ckh_search() failure");
assert_false(ckh_remove(tsdn, &ckh, p[i], &q, &r), assert_false(ckh_remove(tsd, &ckh, p[i], &q, &r),
"Unexpected ckh_remove() failure"); "Unexpected ckh_remove() failure");
assert_ptr_eq(p[i], q, "Key pointer mismatch"); assert_ptr_eq(p[i], q, "Key pointer mismatch");
assert_ptr_eq(p[i], r, "Value pointer mismatch"); assert_ptr_eq(p[i], r, "Value pointer mismatch");
assert_true(ckh_search(&ckh, p[i], NULL, NULL), assert_true(ckh_search(&ckh, p[i], NULL, NULL),
"Unexpected ckh_search() success"); "Unexpected ckh_search() success");
assert_true(ckh_remove(tsdn, &ckh, p[i], &q, &r), assert_true(ckh_remove(tsd, &ckh, p[i], &q, &r),
"Unexpected ckh_remove() success"); "Unexpected ckh_remove() success");
dallocx(p[i], 0); dallocx(p[i], 0);
} }
@@ -198,7 +198,7 @@ TEST_BEGIN(test_insert_iter_remove)
assert_zu_eq(ckh_count(&ckh), 0, assert_zu_eq(ckh_count(&ckh), 0,
"ckh_count() should return %zu, but it returned %zu", "ckh_count() should return %zu, but it returned %zu",
ZU(0), ckh_count(&ckh)); ZU(0), ckh_count(&ckh));
ckh_delete(tsdn, &ckh); ckh_delete(tsd, &ckh);
#undef NITEMS #undef NITEMS
} }
TEST_END TEST_END

View File

@@ -1,21 +1,27 @@
#include "test/jemalloc_test.h" #include "test/jemalloc_test.h"
const char *malloc_conf = "purge:decay,decay_time:1"; static nstime_monotonic_t *nstime_monotonic_orig;
static nstime_update_t *nstime_update_orig; static nstime_update_t *nstime_update_orig;
static unsigned nupdates_mock; static unsigned nupdates_mock;
static nstime_t time_mock; static nstime_t time_mock;
static bool nonmonotonic_mock; static bool monotonic_mock;
static bool
nstime_monotonic_mock(void)
{
return (monotonic_mock);
}
static bool static bool
nstime_update_mock(nstime_t *time) nstime_update_mock(nstime_t *time)
{ {
nupdates_mock++; nupdates_mock++;
if (!nonmonotonic_mock) if (monotonic_mock)
nstime_copy(time, &time_mock); nstime_copy(time, &time_mock);
return (nonmonotonic_mock); return (!monotonic_mock);
} }
TEST_BEGIN(test_decay_ticks) TEST_BEGIN(test_decay_ticks)
@@ -32,10 +38,10 @@ TEST_BEGIN(test_decay_ticks)
"Unexpected failure getting decay ticker"); "Unexpected failure getting decay ticker");
sz = sizeof(size_t); sz = sizeof(size_t);
assert_d_eq(mallctl("arenas.hchunk.0.size", &huge0, &sz, NULL, 0), 0, assert_d_eq(mallctl("arenas.hchunk.0.size", (void *)&huge0, &sz, NULL,
"Unexpected mallctl failure"); 0), 0, "Unexpected mallctl failure");
assert_d_eq(mallctl("arenas.lrun.0.size", &large0, &sz, NULL, 0), 0, assert_d_eq(mallctl("arenas.lrun.0.size", (void *)&large0, &sz, NULL,
"Unexpected mallctl failure"); 0), 0, "Unexpected mallctl failure");
/* /*
* Test the standard APIs using a huge size class, since we can't * Test the standard APIs using a huge size class, since we can't
@@ -167,8 +173,8 @@ TEST_BEGIN(test_decay_ticks)
tcache_sizes[1] = 1; tcache_sizes[1] = 1;
sz = sizeof(unsigned); sz = sizeof(unsigned);
assert_d_eq(mallctl("tcache.create", &tcache_ind, &sz, NULL, 0), assert_d_eq(mallctl("tcache.create", (void *)&tcache_ind, &sz,
0, "Unexpected mallctl failure"); NULL, 0), 0, "Unexpected mallctl failure");
for (i = 0; i < sizeof(tcache_sizes) / sizeof(size_t); i++) { for (i = 0; i < sizeof(tcache_sizes) / sizeof(size_t); i++) {
sz = tcache_sizes[i]; sz = tcache_sizes[i];
@@ -185,7 +191,7 @@ TEST_BEGIN(test_decay_ticks)
dallocx(p, MALLOCX_TCACHE(tcache_ind)); dallocx(p, MALLOCX_TCACHE(tcache_ind));
tick0 = ticker_read(decay_ticker); tick0 = ticker_read(decay_ticker);
assert_d_eq(mallctl("tcache.flush", NULL, NULL, assert_d_eq(mallctl("tcache.flush", NULL, NULL,
&tcache_ind, sizeof(unsigned)), 0, (void *)&tcache_ind, sizeof(unsigned)), 0,
"Unexpected mallctl failure"); "Unexpected mallctl failure");
tick1 = ticker_read(decay_ticker); tick1 = ticker_read(decay_ticker);
assert_u32_ne(tick1, tick0, assert_u32_ne(tick1, tick0,
@@ -220,22 +226,22 @@ TEST_BEGIN(test_decay_ticker)
size_t tcache_max; size_t tcache_max;
sz = sizeof(size_t); sz = sizeof(size_t);
assert_d_eq(mallctl("arenas.tcache_max", &tcache_max, &sz, NULL, assert_d_eq(mallctl("arenas.tcache_max", (void *)&tcache_max,
0), 0, "Unexpected mallctl failure"); &sz, NULL, 0), 0, "Unexpected mallctl failure");
large = nallocx(tcache_max + 1, flags); large = nallocx(tcache_max + 1, flags);
} else { } else {
sz = sizeof(size_t); sz = sizeof(size_t);
assert_d_eq(mallctl("arenas.lrun.0.size", &large, &sz, NULL, 0), assert_d_eq(mallctl("arenas.lrun.0.size", (void *)&large, &sz,
0, "Unexpected mallctl failure"); NULL, 0), 0, "Unexpected mallctl failure");
} }
assert_d_eq(mallctl("arena.0.purge", NULL, NULL, NULL, 0), 0, assert_d_eq(mallctl("arena.0.purge", NULL, NULL, NULL, 0), 0,
"Unexpected mallctl failure"); "Unexpected mallctl failure");
assert_d_eq(mallctl("epoch", NULL, NULL, &epoch, sizeof(uint64_t)), 0, assert_d_eq(mallctl("epoch", NULL, NULL, (void *)&epoch,
"Unexpected mallctl failure"); sizeof(uint64_t)), 0, "Unexpected mallctl failure");
sz = sizeof(uint64_t); sz = sizeof(uint64_t);
assert_d_eq(mallctl("stats.arenas.0.npurge", &npurge0, &sz, NULL, 0), assert_d_eq(mallctl("stats.arenas.0.npurge", (void *)&npurge0, &sz,
config_stats ? 0 : ENOENT, "Unexpected mallctl result"); NULL, 0), config_stats ? 0 : ENOENT, "Unexpected mallctl result");
for (i = 0; i < NPS; i++) { for (i = 0; i < NPS; i++) {
ps[i] = mallocx(large, flags); ps[i] = mallocx(large, flags);
@@ -245,9 +251,11 @@ TEST_BEGIN(test_decay_ticker)
nupdates_mock = 0; nupdates_mock = 0;
nstime_init(&time_mock, 0); nstime_init(&time_mock, 0);
nstime_update(&time_mock); nstime_update(&time_mock);
nonmonotonic_mock = false; monotonic_mock = true;
nstime_monotonic_orig = nstime_monotonic;
nstime_update_orig = nstime_update; nstime_update_orig = nstime_update;
nstime_monotonic = nstime_monotonic_mock;
nstime_update = nstime_update_mock; nstime_update = nstime_update_mock;
for (i = 0; i < NPS; i++) { for (i = 0; i < NPS; i++) {
@@ -259,6 +267,7 @@ TEST_BEGIN(test_decay_ticker)
"Expected nstime_update() to be called"); "Expected nstime_update() to be called");
} }
nstime_monotonic = nstime_monotonic_orig;
nstime_update = nstime_update_orig; nstime_update = nstime_update_orig;
nstime_init(&time, 0); nstime_init(&time, 0);
@@ -272,11 +281,11 @@ TEST_BEGIN(test_decay_ticker)
assert_ptr_not_null(p, "Unexpected mallocx() failure"); assert_ptr_not_null(p, "Unexpected mallocx() failure");
dallocx(p, flags); dallocx(p, flags);
} }
assert_d_eq(mallctl("epoch", NULL, NULL, &epoch, assert_d_eq(mallctl("epoch", NULL, NULL, (void *)&epoch,
sizeof(uint64_t)), 0, "Unexpected mallctl failure"); sizeof(uint64_t)), 0, "Unexpected mallctl failure");
sz = sizeof(uint64_t); sz = sizeof(uint64_t);
assert_d_eq(mallctl("stats.arenas.0.npurge", &npurge1, &sz, assert_d_eq(mallctl("stats.arenas.0.npurge", (void *)&npurge1,
NULL, 0), config_stats ? 0 : ENOENT, &sz, NULL, 0), config_stats ? 0 : ENOENT,
"Unexpected mallctl result"); "Unexpected mallctl result");
nstime_update(&time); nstime_update(&time);
@@ -302,23 +311,25 @@ TEST_BEGIN(test_decay_nonmonotonic)
test_skip_if(opt_purge != purge_mode_decay); test_skip_if(opt_purge != purge_mode_decay);
sz = sizeof(size_t); sz = sizeof(size_t);
assert_d_eq(mallctl("arenas.lrun.0.size", &large0, &sz, NULL, 0), 0, assert_d_eq(mallctl("arenas.lrun.0.size", (void *)&large0, &sz, NULL,
"Unexpected mallctl failure"); 0), 0, "Unexpected mallctl failure");
assert_d_eq(mallctl("arena.0.purge", NULL, NULL, NULL, 0), 0, assert_d_eq(mallctl("arena.0.purge", NULL, NULL, NULL, 0), 0,
"Unexpected mallctl failure"); "Unexpected mallctl failure");
assert_d_eq(mallctl("epoch", NULL, NULL, &epoch, sizeof(uint64_t)), 0, assert_d_eq(mallctl("epoch", NULL, NULL, (void *)&epoch,
"Unexpected mallctl failure"); sizeof(uint64_t)), 0, "Unexpected mallctl failure");
sz = sizeof(uint64_t); sz = sizeof(uint64_t);
assert_d_eq(mallctl("stats.arenas.0.npurge", &npurge0, &sz, NULL, 0), assert_d_eq(mallctl("stats.arenas.0.npurge", (void *)&npurge0, &sz,
config_stats ? 0 : ENOENT, "Unexpected mallctl result"); NULL, 0), config_stats ? 0 : ENOENT, "Unexpected mallctl result");
nupdates_mock = 0; nupdates_mock = 0;
nstime_init(&time_mock, 0); nstime_init(&time_mock, 0);
nstime_update(&time_mock); nstime_update(&time_mock);
nonmonotonic_mock = true; monotonic_mock = false;
nstime_monotonic_orig = nstime_monotonic;
nstime_update_orig = nstime_update; nstime_update_orig = nstime_update;
nstime_monotonic = nstime_monotonic_mock;
nstime_update = nstime_update_mock; nstime_update = nstime_update_mock;
for (i = 0; i < NPS; i++) { for (i = 0; i < NPS; i++) {
@@ -335,15 +346,16 @@ TEST_BEGIN(test_decay_nonmonotonic)
"Expected nstime_update() to be called"); "Expected nstime_update() to be called");
} }
assert_d_eq(mallctl("epoch", NULL, NULL, &epoch, sizeof(uint64_t)), 0, assert_d_eq(mallctl("epoch", NULL, NULL, (void *)&epoch,
"Unexpected mallctl failure"); sizeof(uint64_t)), 0, "Unexpected mallctl failure");
sz = sizeof(uint64_t); sz = sizeof(uint64_t);
assert_d_eq(mallctl("stats.arenas.0.npurge", &npurge1, &sz, NULL, 0), assert_d_eq(mallctl("stats.arenas.0.npurge", (void *)&npurge1, &sz,
config_stats ? 0 : ENOENT, "Unexpected mallctl result"); NULL, 0), config_stats ? 0 : ENOENT, "Unexpected mallctl result");
if (config_stats) if (config_stats)
assert_u64_gt(npurge1, npurge0, "Expected purging to occur"); assert_u64_eq(npurge0, npurge1, "Unexpected purging occurred");
nstime_monotonic = nstime_monotonic_orig;
nstime_update = nstime_update_orig; nstime_update = nstime_update_orig;
#undef NPS #undef NPS
} }

3
test/unit/decay.sh Normal file
View File

@@ -0,0 +1,3 @@
#!/bin/sh
export MALLOC_CONF="purge:decay,decay_time:1"

View File

@@ -0,0 +1,98 @@
#include "test/jemalloc_test.h"
TEST_BEGIN(test_huge_extent_size) {
unsigned nhchunks, i;
size_t sz, extent_size_prev, ceil_prev;
size_t mib[4];
size_t miblen = sizeof(mib) / sizeof(size_t);
/*
* Iterate over all huge size classes, get their extent sizes, and
* verify that the quantized size is the same as the extent size.
*/
sz = sizeof(unsigned);
assert_d_eq(mallctl("arenas.nhchunks", (void *)&nhchunks, &sz, NULL,
0), 0, "Unexpected mallctl failure");
assert_d_eq(mallctlnametomib("arenas.hchunk.0.size", mib, &miblen), 0,
"Unexpected mallctlnametomib failure");
for (i = 0; i < nhchunks; i++) {
size_t extent_size, floor, ceil;
mib[2] = i;
sz = sizeof(size_t);
assert_d_eq(mallctlbymib(mib, miblen, (void *)&extent_size,
&sz, NULL, 0), 0, "Unexpected mallctlbymib failure");
floor = extent_size_quantize_floor(extent_size);
ceil = extent_size_quantize_ceil(extent_size);
assert_zu_eq(extent_size, floor,
"Extent quantization should be a no-op for precise size "
"(extent_size=%zu)", extent_size);
assert_zu_eq(extent_size, ceil,
"Extent quantization should be a no-op for precise size "
"(extent_size=%zu)", extent_size);
if (i > 0) {
assert_zu_eq(extent_size_prev,
extent_size_quantize_floor(extent_size - PAGE),
"Floor should be a precise size");
if (extent_size_prev < ceil_prev) {
assert_zu_eq(ceil_prev, extent_size,
"Ceiling should be a precise size "
"(extent_size_prev=%zu, ceil_prev=%zu, "
"extent_size=%zu)", extent_size_prev,
ceil_prev, extent_size);
}
}
if (i + 1 < nhchunks) {
extent_size_prev = floor;
ceil_prev = extent_size_quantize_ceil(extent_size +
PAGE);
}
}
}
TEST_END
TEST_BEGIN(test_monotonic) {
#define SZ_MAX ZU(4 * 1024 * 1024)
unsigned i;
size_t floor_prev, ceil_prev;
floor_prev = 0;
ceil_prev = 0;
for (i = 1; i <= SZ_MAX >> LG_PAGE; i++) {
size_t extent_size, floor, ceil;
extent_size = i << LG_PAGE;
floor = extent_size_quantize_floor(extent_size);
ceil = extent_size_quantize_ceil(extent_size);
assert_zu_le(floor, extent_size,
"Floor should be <= (floor=%zu, extent_size=%zu, ceil=%zu)",
floor, extent_size, ceil);
assert_zu_ge(ceil, extent_size,
"Ceiling should be >= (floor=%zu, extent_size=%zu, "
"ceil=%zu)", floor, extent_size, ceil);
assert_zu_le(floor_prev, floor, "Floor should be monotonic "
"(floor_prev=%zu, floor=%zu, extent_size=%zu, ceil=%zu)",
floor_prev, floor, extent_size, ceil);
assert_zu_le(ceil_prev, ceil, "Ceiling should be monotonic "
"(floor=%zu, extent_size=%zu, ceil_prev=%zu, ceil=%zu)",
floor, extent_size, ceil_prev, ceil);
floor_prev = floor;
ceil_prev = ceil;
}
}
TEST_END
int
main(void) {
return test(
test_huge_extent_size,
test_monotonic);
}

View File

@@ -26,7 +26,7 @@ TEST_BEGIN(test_fork)
test_fail("Unexpected fork() failure"); test_fail("Unexpected fork() failure");
} else if (pid == 0) { } else if (pid == 0) {
/* Child. */ /* Child. */
exit(0); _exit(0);
} else { } else {
int status; int status;

View File

@@ -1,13 +1,5 @@
#include "test/jemalloc_test.h" #include "test/jemalloc_test.h"
#ifdef JEMALLOC_FILL
# ifndef JEMALLOC_TEST_JUNK_OPT
# define JEMALLOC_TEST_JUNK_OPT "junk:true"
# endif
const char *malloc_conf =
"abort:false,zero:false,redzone:true,quarantine:0," JEMALLOC_TEST_JUNK_OPT;
#endif
static arena_dalloc_junk_small_t *arena_dalloc_junk_small_orig; static arena_dalloc_junk_small_t *arena_dalloc_junk_small_orig;
static arena_dalloc_junk_large_t *arena_dalloc_junk_large_orig; static arena_dalloc_junk_large_t *arena_dalloc_junk_large_orig;
static huge_dalloc_junk_t *huge_dalloc_junk_orig; static huge_dalloc_junk_t *huge_dalloc_junk_orig;
@@ -53,10 +45,10 @@ arena_dalloc_junk_large_intercept(void *ptr, size_t usize)
} }
static void static void
huge_dalloc_junk_intercept(tsdn_t *tsdn, void *ptr, size_t usize) huge_dalloc_junk_intercept(void *ptr, size_t usize)
{ {
huge_dalloc_junk_orig(tsdn, ptr, usize); huge_dalloc_junk_orig(ptr, usize);
/* /*
* The conditions under which junk filling actually occurs are nuanced * The conditions under which junk filling actually occurs are nuanced
* enough that it doesn't make sense to duplicate the decision logic in * enough that it doesn't make sense to duplicate the decision logic in

5
test/unit/junk.sh Normal file
View File

@@ -0,0 +1,5 @@
#!/bin/sh
if [ "x${enable_fill}" = "x1" ] ; then
export MALLOC_CONF="abort:false,zero:false,redzone:true,quarantine:0,junk:true"
fi

View File

@@ -1,3 +1 @@
#define JEMALLOC_TEST_JUNK_OPT "junk:alloc"
#include "junk.c" #include "junk.c"
#undef JEMALLOC_TEST_JUNK_OPT

5
test/unit/junk_alloc.sh Normal file
View File

@@ -0,0 +1,5 @@
#!/bin/sh
if [ "x${enable_fill}" = "x1" ] ; then
export MALLOC_CONF="abort:false,zero:false,redzone:true,quarantine:0,junk:alloc"
fi

View File

@@ -1,3 +1 @@
#define JEMALLOC_TEST_JUNK_OPT "junk:free"
#include "junk.c" #include "junk.c"
#undef JEMALLOC_TEST_JUNK_OPT

5
test/unit/junk_free.sh Normal file
View File

@@ -0,0 +1,5 @@
#!/bin/sh
if [ "x${enable_fill}" = "x1" ] ; then
export MALLOC_CONF="abort:false,zero:false,redzone:true,quarantine:0,junk:free"
fi

View File

@@ -1,12 +1,5 @@
#include "test/jemalloc_test.h" #include "test/jemalloc_test.h"
/*
* Make sure that opt.lg_chunk clamping is sufficient. In practice, this test
* program will fail a debug assertion during initialization and abort (rather
* than the test soft-failing) if clamping is insufficient.
*/
const char *malloc_conf = "lg_chunk:0";
TEST_BEGIN(test_lg_chunk_clamp) TEST_BEGIN(test_lg_chunk_clamp)
{ {
void *p; void *p;

6
test/unit/lg_chunk.sh Normal file
View File

@@ -0,0 +1,6 @@
#!/bin/sh
# Make sure that opt.lg_chunk clamping is sufficient. In practice, this test
# program will fail a debug assertion during initialization and abort (rather
# than the test soft-failing) if clamping is insufficient.
export MALLOC_CONF="lg_chunk:0"

View File

@@ -12,16 +12,18 @@ TEST_BEGIN(test_mallctl_errors)
EPERM, "mallctl() should return EPERM on attempt to write " EPERM, "mallctl() should return EPERM on attempt to write "
"read-only value"); "read-only value");
assert_d_eq(mallctl("epoch", NULL, NULL, &epoch, sizeof(epoch)-1), assert_d_eq(mallctl("epoch", NULL, NULL, (void *)&epoch,
EINVAL, "mallctl() should return EINVAL for input size mismatch"); sizeof(epoch)-1), EINVAL,
assert_d_eq(mallctl("epoch", NULL, NULL, &epoch, sizeof(epoch)+1), "mallctl() should return EINVAL for input size mismatch");
EINVAL, "mallctl() should return EINVAL for input size mismatch"); assert_d_eq(mallctl("epoch", NULL, NULL, (void *)&epoch,
sizeof(epoch)+1), EINVAL,
"mallctl() should return EINVAL for input size mismatch");
sz = sizeof(epoch)-1; sz = sizeof(epoch)-1;
assert_d_eq(mallctl("epoch", &epoch, &sz, NULL, 0), EINVAL, assert_d_eq(mallctl("epoch", (void *)&epoch, &sz, NULL, 0), EINVAL,
"mallctl() should return EINVAL for output size mismatch"); "mallctl() should return EINVAL for output size mismatch");
sz = sizeof(epoch)+1; sz = sizeof(epoch)+1;
assert_d_eq(mallctl("epoch", &epoch, &sz, NULL, 0), EINVAL, assert_d_eq(mallctl("epoch", (void *)&epoch, &sz, NULL, 0), EINVAL,
"mallctl() should return EINVAL for output size mismatch"); "mallctl() should return EINVAL for output size mismatch");
} }
TEST_END TEST_END
@@ -56,18 +58,20 @@ TEST_BEGIN(test_mallctlbymib_errors)
assert_d_eq(mallctlnametomib("epoch", mib, &miblen), 0, assert_d_eq(mallctlnametomib("epoch", mib, &miblen), 0,
"Unexpected mallctlnametomib() failure"); "Unexpected mallctlnametomib() failure");
assert_d_eq(mallctlbymib(mib, miblen, NULL, NULL, &epoch, assert_d_eq(mallctlbymib(mib, miblen, NULL, NULL, (void *)&epoch,
sizeof(epoch)-1), EINVAL, sizeof(epoch)-1), EINVAL,
"mallctlbymib() should return EINVAL for input size mismatch"); "mallctlbymib() should return EINVAL for input size mismatch");
assert_d_eq(mallctlbymib(mib, miblen, NULL, NULL, &epoch, assert_d_eq(mallctlbymib(mib, miblen, NULL, NULL, (void *)&epoch,
sizeof(epoch)+1), EINVAL, sizeof(epoch)+1), EINVAL,
"mallctlbymib() should return EINVAL for input size mismatch"); "mallctlbymib() should return EINVAL for input size mismatch");
sz = sizeof(epoch)-1; sz = sizeof(epoch)-1;
assert_d_eq(mallctlbymib(mib, miblen, &epoch, &sz, NULL, 0), EINVAL, assert_d_eq(mallctlbymib(mib, miblen, (void *)&epoch, &sz, NULL, 0),
EINVAL,
"mallctlbymib() should return EINVAL for output size mismatch"); "mallctlbymib() should return EINVAL for output size mismatch");
sz = sizeof(epoch)+1; sz = sizeof(epoch)+1;
assert_d_eq(mallctlbymib(mib, miblen, &epoch, &sz, NULL, 0), EINVAL, assert_d_eq(mallctlbymib(mib, miblen, (void *)&epoch, &sz, NULL, 0),
EINVAL,
"mallctlbymib() should return EINVAL for output size mismatch"); "mallctlbymib() should return EINVAL for output size mismatch");
} }
TEST_END TEST_END
@@ -83,18 +87,19 @@ TEST_BEGIN(test_mallctl_read_write)
assert_zu_eq(sz, sizeof(old_epoch), "Unexpected output size"); assert_zu_eq(sz, sizeof(old_epoch), "Unexpected output size");
/* Read. */ /* Read. */
assert_d_eq(mallctl("epoch", &old_epoch, &sz, NULL, 0), 0, assert_d_eq(mallctl("epoch", (void *)&old_epoch, &sz, NULL, 0), 0,
"Unexpected mallctl() failure"); "Unexpected mallctl() failure");
assert_zu_eq(sz, sizeof(old_epoch), "Unexpected output size"); assert_zu_eq(sz, sizeof(old_epoch), "Unexpected output size");
/* Write. */ /* Write. */
assert_d_eq(mallctl("epoch", NULL, NULL, &new_epoch, sizeof(new_epoch)), assert_d_eq(mallctl("epoch", NULL, NULL, (void *)&new_epoch,
0, "Unexpected mallctl() failure"); sizeof(new_epoch)), 0, "Unexpected mallctl() failure");
assert_zu_eq(sz, sizeof(old_epoch), "Unexpected output size"); assert_zu_eq(sz, sizeof(old_epoch), "Unexpected output size");
/* Read+write. */ /* Read+write. */
assert_d_eq(mallctl("epoch", &old_epoch, &sz, &new_epoch, assert_d_eq(mallctl("epoch", (void *)&old_epoch, &sz,
sizeof(new_epoch)), 0, "Unexpected mallctl() failure"); (void *)&new_epoch, sizeof(new_epoch)), 0,
"Unexpected mallctl() failure");
assert_zu_eq(sz, sizeof(old_epoch), "Unexpected output size"); assert_zu_eq(sz, sizeof(old_epoch), "Unexpected output size");
} }
TEST_END TEST_END
@@ -120,8 +125,8 @@ TEST_BEGIN(test_mallctl_config)
#define TEST_MALLCTL_CONFIG(config, t) do { \ #define TEST_MALLCTL_CONFIG(config, t) do { \
t oldval; \ t oldval; \
size_t sz = sizeof(oldval); \ size_t sz = sizeof(oldval); \
assert_d_eq(mallctl("config."#config, &oldval, &sz, NULL, 0), \ assert_d_eq(mallctl("config."#config, (void *)&oldval, &sz, \
0, "Unexpected mallctl() failure"); \ NULL, 0), 0, "Unexpected mallctl() failure"); \
assert_b_eq(oldval, config_##config, "Incorrect config value"); \ assert_b_eq(oldval, config_##config, "Incorrect config value"); \
assert_zu_eq(sz, sizeof(oldval), "Unexpected output size"); \ assert_zu_eq(sz, sizeof(oldval), "Unexpected output size"); \
} while (0) } while (0)
@@ -137,6 +142,7 @@ TEST_BEGIN(test_mallctl_config)
TEST_MALLCTL_CONFIG(prof_libunwind, bool); TEST_MALLCTL_CONFIG(prof_libunwind, bool);
TEST_MALLCTL_CONFIG(stats, bool); TEST_MALLCTL_CONFIG(stats, bool);
TEST_MALLCTL_CONFIG(tcache, bool); TEST_MALLCTL_CONFIG(tcache, bool);
TEST_MALLCTL_CONFIG(thp, bool);
TEST_MALLCTL_CONFIG(tls, bool); TEST_MALLCTL_CONFIG(tls, bool);
TEST_MALLCTL_CONFIG(utrace, bool); TEST_MALLCTL_CONFIG(utrace, bool);
TEST_MALLCTL_CONFIG(valgrind, bool); TEST_MALLCTL_CONFIG(valgrind, bool);
@@ -154,7 +160,8 @@ TEST_BEGIN(test_mallctl_opt)
t oldval; \ t oldval; \
size_t sz = sizeof(oldval); \ size_t sz = sizeof(oldval); \
int expected = config_##config ? 0 : ENOENT; \ int expected = config_##config ? 0 : ENOENT; \
int result = mallctl("opt."#opt, &oldval, &sz, NULL, 0); \ int result = mallctl("opt."#opt, (void *)&oldval, &sz, NULL, \
0); \
assert_d_eq(result, expected, \ assert_d_eq(result, expected, \
"Unexpected mallctl() result for opt."#opt); \ "Unexpected mallctl() result for opt."#opt); \
assert_zu_eq(sz, sizeof(oldval), "Unexpected output size"); \ assert_zu_eq(sz, sizeof(oldval), "Unexpected output size"); \
@@ -176,6 +183,7 @@ TEST_BEGIN(test_mallctl_opt)
TEST_MALLCTL_OPT(bool, xmalloc, xmalloc); TEST_MALLCTL_OPT(bool, xmalloc, xmalloc);
TEST_MALLCTL_OPT(bool, tcache, tcache); TEST_MALLCTL_OPT(bool, tcache, tcache);
TEST_MALLCTL_OPT(size_t, lg_tcache_max, tcache); TEST_MALLCTL_OPT(size_t, lg_tcache_max, tcache);
TEST_MALLCTL_OPT(bool, thp, thp);
TEST_MALLCTL_OPT(bool, prof, prof); TEST_MALLCTL_OPT(bool, prof, prof);
TEST_MALLCTL_OPT(const char *, prof_prefix, prof); TEST_MALLCTL_OPT(const char *, prof_prefix, prof);
TEST_MALLCTL_OPT(bool, prof_active, prof); TEST_MALLCTL_OPT(bool, prof_active, prof);
@@ -197,7 +205,7 @@ TEST_BEGIN(test_manpage_example)
size_t len, miblen; size_t len, miblen;
len = sizeof(nbins); len = sizeof(nbins);
assert_d_eq(mallctl("arenas.nbins", &nbins, &len, NULL, 0), 0, assert_d_eq(mallctl("arenas.nbins", (void *)&nbins, &len, NULL, 0), 0,
"Unexpected mallctl() failure"); "Unexpected mallctl() failure");
miblen = 4; miblen = 4;
@@ -208,8 +216,8 @@ TEST_BEGIN(test_manpage_example)
mib[2] = i; mib[2] = i;
len = sizeof(bin_size); len = sizeof(bin_size);
assert_d_eq(mallctlbymib(mib, miblen, &bin_size, &len, NULL, 0), assert_d_eq(mallctlbymib(mib, miblen, (void *)&bin_size, &len,
0, "Unexpected mallctlbymib() failure"); NULL, 0), 0, "Unexpected mallctlbymib() failure");
/* Do something with bin_size... */ /* Do something with bin_size... */
} }
} }
@@ -258,25 +266,25 @@ TEST_BEGIN(test_tcache)
/* Create tcaches. */ /* Create tcaches. */
for (i = 0; i < NTCACHES; i++) { for (i = 0; i < NTCACHES; i++) {
sz = sizeof(unsigned); sz = sizeof(unsigned);
assert_d_eq(mallctl("tcache.create", &tis[i], &sz, NULL, 0), 0, assert_d_eq(mallctl("tcache.create", (void *)&tis[i], &sz, NULL,
"Unexpected mallctl() failure, i=%u", i); 0), 0, "Unexpected mallctl() failure, i=%u", i);
} }
/* Exercise tcache ID recycling. */ /* Exercise tcache ID recycling. */
for (i = 0; i < NTCACHES; i++) { for (i = 0; i < NTCACHES; i++) {
assert_d_eq(mallctl("tcache.destroy", NULL, NULL, &tis[i], assert_d_eq(mallctl("tcache.destroy", NULL, NULL,
sizeof(unsigned)), 0, "Unexpected mallctl() failure, i=%u", (void *)&tis[i], sizeof(unsigned)), 0,
i); "Unexpected mallctl() failure, i=%u", i);
} }
for (i = 0; i < NTCACHES; i++) { for (i = 0; i < NTCACHES; i++) {
sz = sizeof(unsigned); sz = sizeof(unsigned);
assert_d_eq(mallctl("tcache.create", &tis[i], &sz, NULL, 0), 0, assert_d_eq(mallctl("tcache.create", (void *)&tis[i], &sz, NULL,
"Unexpected mallctl() failure, i=%u", i); 0), 0, "Unexpected mallctl() failure, i=%u", i);
} }
/* Flush empty tcaches. */ /* Flush empty tcaches. */
for (i = 0; i < NTCACHES; i++) { for (i = 0; i < NTCACHES; i++) {
assert_d_eq(mallctl("tcache.flush", NULL, NULL, &tis[i], assert_d_eq(mallctl("tcache.flush", NULL, NULL, (void *)&tis[i],
sizeof(unsigned)), 0, "Unexpected mallctl() failure, i=%u", sizeof(unsigned)), 0, "Unexpected mallctl() failure, i=%u",
i); i);
} }
@@ -321,16 +329,16 @@ TEST_BEGIN(test_tcache)
/* Flush some non-empty tcaches. */ /* Flush some non-empty tcaches. */
for (i = 0; i < NTCACHES/2; i++) { for (i = 0; i < NTCACHES/2; i++) {
assert_d_eq(mallctl("tcache.flush", NULL, NULL, &tis[i], assert_d_eq(mallctl("tcache.flush", NULL, NULL, (void *)&tis[i],
sizeof(unsigned)), 0, "Unexpected mallctl() failure, i=%u", sizeof(unsigned)), 0, "Unexpected mallctl() failure, i=%u",
i); i);
} }
/* Destroy tcaches. */ /* Destroy tcaches. */
for (i = 0; i < NTCACHES; i++) { for (i = 0; i < NTCACHES; i++) {
assert_d_eq(mallctl("tcache.destroy", NULL, NULL, &tis[i], assert_d_eq(mallctl("tcache.destroy", NULL, NULL,
sizeof(unsigned)), 0, "Unexpected mallctl() failure, i=%u", (void *)&tis[i], sizeof(unsigned)), 0,
i); "Unexpected mallctl() failure, i=%u", i);
} }
} }
TEST_END TEST_END
@@ -340,15 +348,17 @@ TEST_BEGIN(test_thread_arena)
unsigned arena_old, arena_new, narenas; unsigned arena_old, arena_new, narenas;
size_t sz = sizeof(unsigned); size_t sz = sizeof(unsigned);
assert_d_eq(mallctl("arenas.narenas", &narenas, &sz, NULL, 0), 0, assert_d_eq(mallctl("arenas.narenas", (void *)&narenas, &sz, NULL, 0),
"Unexpected mallctl() failure"); 0, "Unexpected mallctl() failure");
assert_u_eq(narenas, opt_narenas, "Number of arenas incorrect"); assert_u_eq(narenas, opt_narenas, "Number of arenas incorrect");
arena_new = narenas - 1; arena_new = narenas - 1;
assert_d_eq(mallctl("thread.arena", &arena_old, &sz, &arena_new, assert_d_eq(mallctl("thread.arena", (void *)&arena_old, &sz,
sizeof(unsigned)), 0, "Unexpected mallctl() failure"); (void *)&arena_new, sizeof(unsigned)), 0,
"Unexpected mallctl() failure");
arena_new = 0; arena_new = 0;
assert_d_eq(mallctl("thread.arena", &arena_old, &sz, &arena_new, assert_d_eq(mallctl("thread.arena", (void *)&arena_old, &sz,
sizeof(unsigned)), 0, "Unexpected mallctl() failure"); (void *)&arena_new, sizeof(unsigned)), 0,
"Unexpected mallctl() failure");
} }
TEST_END TEST_END
@@ -359,17 +369,18 @@ TEST_BEGIN(test_arena_i_lg_dirty_mult)
test_skip_if(opt_purge != purge_mode_ratio); test_skip_if(opt_purge != purge_mode_ratio);
assert_d_eq(mallctl("arena.0.lg_dirty_mult", &orig_lg_dirty_mult, &sz, assert_d_eq(mallctl("arena.0.lg_dirty_mult",
NULL, 0), 0, "Unexpected mallctl() failure"); (void *)&orig_lg_dirty_mult, &sz, NULL, 0), 0,
"Unexpected mallctl() failure");
lg_dirty_mult = -2; lg_dirty_mult = -2;
assert_d_eq(mallctl("arena.0.lg_dirty_mult", NULL, NULL, assert_d_eq(mallctl("arena.0.lg_dirty_mult", NULL, NULL,
&lg_dirty_mult, sizeof(ssize_t)), EFAULT, (void *)&lg_dirty_mult, sizeof(ssize_t)), EFAULT,
"Unexpected mallctl() success"); "Unexpected mallctl() success");
lg_dirty_mult = (sizeof(size_t) << 3); lg_dirty_mult = (sizeof(size_t) << 3);
assert_d_eq(mallctl("arena.0.lg_dirty_mult", NULL, NULL, assert_d_eq(mallctl("arena.0.lg_dirty_mult", NULL, NULL,
&lg_dirty_mult, sizeof(ssize_t)), EFAULT, (void *)&lg_dirty_mult, sizeof(ssize_t)), EFAULT,
"Unexpected mallctl() success"); "Unexpected mallctl() success");
for (prev_lg_dirty_mult = orig_lg_dirty_mult, lg_dirty_mult = -1; for (prev_lg_dirty_mult = orig_lg_dirty_mult, lg_dirty_mult = -1;
@@ -377,9 +388,9 @@ TEST_BEGIN(test_arena_i_lg_dirty_mult)
= lg_dirty_mult, lg_dirty_mult++) { = lg_dirty_mult, lg_dirty_mult++) {
ssize_t old_lg_dirty_mult; ssize_t old_lg_dirty_mult;
assert_d_eq(mallctl("arena.0.lg_dirty_mult", &old_lg_dirty_mult, assert_d_eq(mallctl("arena.0.lg_dirty_mult",
&sz, &lg_dirty_mult, sizeof(ssize_t)), 0, (void *)&old_lg_dirty_mult, &sz, (void *)&lg_dirty_mult,
"Unexpected mallctl() failure"); sizeof(ssize_t)), 0, "Unexpected mallctl() failure");
assert_zd_eq(old_lg_dirty_mult, prev_lg_dirty_mult, assert_zd_eq(old_lg_dirty_mult, prev_lg_dirty_mult,
"Unexpected old arena.0.lg_dirty_mult"); "Unexpected old arena.0.lg_dirty_mult");
} }
@@ -393,25 +404,25 @@ TEST_BEGIN(test_arena_i_decay_time)
test_skip_if(opt_purge != purge_mode_decay); test_skip_if(opt_purge != purge_mode_decay);
assert_d_eq(mallctl("arena.0.decay_time", &orig_decay_time, &sz, assert_d_eq(mallctl("arena.0.decay_time", (void *)&orig_decay_time, &sz,
NULL, 0), 0, "Unexpected mallctl() failure"); NULL, 0), 0, "Unexpected mallctl() failure");
decay_time = -2; decay_time = -2;
assert_d_eq(mallctl("arena.0.decay_time", NULL, NULL, assert_d_eq(mallctl("arena.0.decay_time", NULL, NULL,
&decay_time, sizeof(ssize_t)), EFAULT, (void *)&decay_time, sizeof(ssize_t)), EFAULT,
"Unexpected mallctl() success"); "Unexpected mallctl() success");
decay_time = 0x7fffffff; decay_time = 0x7fffffff;
assert_d_eq(mallctl("arena.0.decay_time", NULL, NULL, assert_d_eq(mallctl("arena.0.decay_time", NULL, NULL,
&decay_time, sizeof(ssize_t)), 0, (void *)&decay_time, sizeof(ssize_t)), 0,
"Unexpected mallctl() failure"); "Unexpected mallctl() failure");
for (prev_decay_time = decay_time, decay_time = -1; for (prev_decay_time = decay_time, decay_time = -1;
decay_time < 20; prev_decay_time = decay_time, decay_time++) { decay_time < 20; prev_decay_time = decay_time, decay_time++) {
ssize_t old_decay_time; ssize_t old_decay_time;
assert_d_eq(mallctl("arena.0.decay_time", &old_decay_time, assert_d_eq(mallctl("arena.0.decay_time", (void *)&old_decay_time,
&sz, &decay_time, sizeof(ssize_t)), 0, &sz, (void *)&decay_time, sizeof(ssize_t)), 0,
"Unexpected mallctl() failure"); "Unexpected mallctl() failure");
assert_zd_eq(old_decay_time, prev_decay_time, assert_zd_eq(old_decay_time, prev_decay_time,
"Unexpected old arena.0.decay_time"); "Unexpected old arena.0.decay_time");
@@ -429,8 +440,8 @@ TEST_BEGIN(test_arena_i_purge)
assert_d_eq(mallctl("arena.0.purge", NULL, NULL, NULL, 0), 0, assert_d_eq(mallctl("arena.0.purge", NULL, NULL, NULL, 0), 0,
"Unexpected mallctl() failure"); "Unexpected mallctl() failure");
assert_d_eq(mallctl("arenas.narenas", &narenas, &sz, NULL, 0), 0, assert_d_eq(mallctl("arenas.narenas", (void *)&narenas, &sz, NULL, 0),
"Unexpected mallctl() failure"); 0, "Unexpected mallctl() failure");
assert_d_eq(mallctlnametomib("arena.0.purge", mib, &miblen), 0, assert_d_eq(mallctlnametomib("arena.0.purge", mib, &miblen), 0,
"Unexpected mallctlnametomib() failure"); "Unexpected mallctlnametomib() failure");
mib[1] = narenas; mib[1] = narenas;
@@ -449,8 +460,8 @@ TEST_BEGIN(test_arena_i_decay)
assert_d_eq(mallctl("arena.0.decay", NULL, NULL, NULL, 0), 0, assert_d_eq(mallctl("arena.0.decay", NULL, NULL, NULL, 0), 0,
"Unexpected mallctl() failure"); "Unexpected mallctl() failure");
assert_d_eq(mallctl("arenas.narenas", &narenas, &sz, NULL, 0), 0, assert_d_eq(mallctl("arenas.narenas", (void *)&narenas, &sz, NULL, 0),
"Unexpected mallctl() failure"); 0, "Unexpected mallctl() failure");
assert_d_eq(mallctlnametomib("arena.0.decay", mib, &miblen), 0, assert_d_eq(mallctlnametomib("arena.0.decay", mib, &miblen), 0,
"Unexpected mallctlnametomib() failure"); "Unexpected mallctlnametomib() failure");
mib[1] = narenas; mib[1] = narenas;
@@ -471,31 +482,35 @@ TEST_BEGIN(test_arena_i_dss)
"Unexpected mallctlnametomib() error"); "Unexpected mallctlnametomib() error");
dss_prec_new = "disabled"; dss_prec_new = "disabled";
assert_d_eq(mallctlbymib(mib, miblen, &dss_prec_old, &sz, &dss_prec_new, assert_d_eq(mallctlbymib(mib, miblen, (void *)&dss_prec_old, &sz,
sizeof(dss_prec_new)), 0, "Unexpected mallctl() failure"); (void *)&dss_prec_new, sizeof(dss_prec_new)), 0,
"Unexpected mallctl() failure");
assert_str_ne(dss_prec_old, "primary", assert_str_ne(dss_prec_old, "primary",
"Unexpected default for dss precedence"); "Unexpected default for dss precedence");
assert_d_eq(mallctlbymib(mib, miblen, &dss_prec_new, &sz, &dss_prec_old, assert_d_eq(mallctlbymib(mib, miblen, (void *)&dss_prec_new, &sz,
sizeof(dss_prec_old)), 0, "Unexpected mallctl() failure"); (void *)&dss_prec_old, sizeof(dss_prec_old)), 0,
assert_d_eq(mallctlbymib(mib, miblen, &dss_prec_old, &sz, NULL, 0), 0,
"Unexpected mallctl() failure"); "Unexpected mallctl() failure");
assert_d_eq(mallctlbymib(mib, miblen, (void *)&dss_prec_old, &sz, NULL,
0), 0, "Unexpected mallctl() failure");
assert_str_ne(dss_prec_old, "primary", assert_str_ne(dss_prec_old, "primary",
"Unexpected value for dss precedence"); "Unexpected value for dss precedence");
mib[1] = narenas_total_get(); mib[1] = narenas_total_get();
dss_prec_new = "disabled"; dss_prec_new = "disabled";
assert_d_eq(mallctlbymib(mib, miblen, &dss_prec_old, &sz, &dss_prec_new, assert_d_eq(mallctlbymib(mib, miblen, (void *)&dss_prec_old, &sz,
sizeof(dss_prec_new)), 0, "Unexpected mallctl() failure"); (void *)&dss_prec_new, sizeof(dss_prec_new)), 0,
"Unexpected mallctl() failure");
assert_str_ne(dss_prec_old, "primary", assert_str_ne(dss_prec_old, "primary",
"Unexpected default for dss precedence"); "Unexpected default for dss precedence");
assert_d_eq(mallctlbymib(mib, miblen, &dss_prec_new, &sz, &dss_prec_old, assert_d_eq(mallctlbymib(mib, miblen, (void *)&dss_prec_new, &sz,
sizeof(dss_prec_new)), 0, "Unexpected mallctl() failure"); (void *)&dss_prec_old, sizeof(dss_prec_new)), 0,
assert_d_eq(mallctlbymib(mib, miblen, &dss_prec_old, &sz, NULL, 0), 0,
"Unexpected mallctl() failure"); "Unexpected mallctl() failure");
assert_d_eq(mallctlbymib(mib, miblen, (void *)&dss_prec_old, &sz, NULL,
0), 0, "Unexpected mallctl() failure");
assert_str_ne(dss_prec_old, "primary", assert_str_ne(dss_prec_old, "primary",
"Unexpected value for dss precedence"); "Unexpected value for dss precedence");
} }
@@ -506,14 +521,14 @@ TEST_BEGIN(test_arenas_initialized)
unsigned narenas; unsigned narenas;
size_t sz = sizeof(narenas); size_t sz = sizeof(narenas);
assert_d_eq(mallctl("arenas.narenas", &narenas, &sz, NULL, 0), 0, assert_d_eq(mallctl("arenas.narenas", (void *)&narenas, &sz, NULL, 0),
"Unexpected mallctl() failure"); 0, "Unexpected mallctl() failure");
{ {
VARIABLE_ARRAY(bool, initialized, narenas); VARIABLE_ARRAY(bool, initialized, narenas);
sz = narenas * sizeof(bool); sz = narenas * sizeof(bool);
assert_d_eq(mallctl("arenas.initialized", initialized, &sz, assert_d_eq(mallctl("arenas.initialized", (void *)initialized,
NULL, 0), 0, "Unexpected mallctl() failure"); &sz, NULL, 0), 0, "Unexpected mallctl() failure");
} }
} }
TEST_END TEST_END
@@ -525,17 +540,17 @@ TEST_BEGIN(test_arenas_lg_dirty_mult)
test_skip_if(opt_purge != purge_mode_ratio); test_skip_if(opt_purge != purge_mode_ratio);
assert_d_eq(mallctl("arenas.lg_dirty_mult", &orig_lg_dirty_mult, &sz, assert_d_eq(mallctl("arenas.lg_dirty_mult", (void *)&orig_lg_dirty_mult,
NULL, 0), 0, "Unexpected mallctl() failure"); &sz, NULL, 0), 0, "Unexpected mallctl() failure");
lg_dirty_mult = -2; lg_dirty_mult = -2;
assert_d_eq(mallctl("arenas.lg_dirty_mult", NULL, NULL, assert_d_eq(mallctl("arenas.lg_dirty_mult", NULL, NULL,
&lg_dirty_mult, sizeof(ssize_t)), EFAULT, (void *)&lg_dirty_mult, sizeof(ssize_t)), EFAULT,
"Unexpected mallctl() success"); "Unexpected mallctl() success");
lg_dirty_mult = (sizeof(size_t) << 3); lg_dirty_mult = (sizeof(size_t) << 3);
assert_d_eq(mallctl("arenas.lg_dirty_mult", NULL, NULL, assert_d_eq(mallctl("arenas.lg_dirty_mult", NULL, NULL,
&lg_dirty_mult, sizeof(ssize_t)), EFAULT, (void *)&lg_dirty_mult, sizeof(ssize_t)), EFAULT,
"Unexpected mallctl() success"); "Unexpected mallctl() success");
for (prev_lg_dirty_mult = orig_lg_dirty_mult, lg_dirty_mult = -1; for (prev_lg_dirty_mult = orig_lg_dirty_mult, lg_dirty_mult = -1;
@@ -543,9 +558,9 @@ TEST_BEGIN(test_arenas_lg_dirty_mult)
lg_dirty_mult, lg_dirty_mult++) { lg_dirty_mult, lg_dirty_mult++) {
ssize_t old_lg_dirty_mult; ssize_t old_lg_dirty_mult;
assert_d_eq(mallctl("arenas.lg_dirty_mult", &old_lg_dirty_mult, assert_d_eq(mallctl("arenas.lg_dirty_mult",
&sz, &lg_dirty_mult, sizeof(ssize_t)), 0, (void *)&old_lg_dirty_mult, &sz, (void *)&lg_dirty_mult,
"Unexpected mallctl() failure"); sizeof(ssize_t)), 0, "Unexpected mallctl() failure");
assert_zd_eq(old_lg_dirty_mult, prev_lg_dirty_mult, assert_zd_eq(old_lg_dirty_mult, prev_lg_dirty_mult,
"Unexpected old arenas.lg_dirty_mult"); "Unexpected old arenas.lg_dirty_mult");
} }
@@ -559,26 +574,26 @@ TEST_BEGIN(test_arenas_decay_time)
test_skip_if(opt_purge != purge_mode_decay); test_skip_if(opt_purge != purge_mode_decay);
assert_d_eq(mallctl("arenas.decay_time", &orig_decay_time, &sz, assert_d_eq(mallctl("arenas.decay_time", (void *)&orig_decay_time, &sz,
NULL, 0), 0, "Unexpected mallctl() failure"); NULL, 0), 0, "Unexpected mallctl() failure");
decay_time = -2; decay_time = -2;
assert_d_eq(mallctl("arenas.decay_time", NULL, NULL, assert_d_eq(mallctl("arenas.decay_time", NULL, NULL,
&decay_time, sizeof(ssize_t)), EFAULT, (void *)&decay_time, sizeof(ssize_t)), EFAULT,
"Unexpected mallctl() success"); "Unexpected mallctl() success");
decay_time = 0x7fffffff; decay_time = 0x7fffffff;
assert_d_eq(mallctl("arenas.decay_time", NULL, NULL, assert_d_eq(mallctl("arenas.decay_time", NULL, NULL,
&decay_time, sizeof(ssize_t)), 0, (void *)&decay_time, sizeof(ssize_t)), 0,
"Expected mallctl() failure"); "Expected mallctl() failure");
for (prev_decay_time = decay_time, decay_time = -1; for (prev_decay_time = decay_time, decay_time = -1;
decay_time < 20; prev_decay_time = decay_time, decay_time++) { decay_time < 20; prev_decay_time = decay_time, decay_time++) {
ssize_t old_decay_time; ssize_t old_decay_time;
assert_d_eq(mallctl("arenas.decay_time", &old_decay_time, assert_d_eq(mallctl("arenas.decay_time",
&sz, &decay_time, sizeof(ssize_t)), 0, (void *)&old_decay_time, &sz, (void *)&decay_time,
"Unexpected mallctl() failure"); sizeof(ssize_t)), 0, "Unexpected mallctl() failure");
assert_zd_eq(old_decay_time, prev_decay_time, assert_zd_eq(old_decay_time, prev_decay_time,
"Unexpected old arenas.decay_time"); "Unexpected old arenas.decay_time");
} }
@@ -591,8 +606,8 @@ TEST_BEGIN(test_arenas_constants)
#define TEST_ARENAS_CONSTANT(t, name, expected) do { \ #define TEST_ARENAS_CONSTANT(t, name, expected) do { \
t name; \ t name; \
size_t sz = sizeof(t); \ size_t sz = sizeof(t); \
assert_d_eq(mallctl("arenas."#name, &name, &sz, NULL, 0), 0, \ assert_d_eq(mallctl("arenas."#name, (void *)&name, &sz, NULL, \
"Unexpected mallctl() failure"); \ 0), 0, "Unexpected mallctl() failure"); \
assert_zu_eq(name, expected, "Incorrect "#name" size"); \ assert_zu_eq(name, expected, "Incorrect "#name" size"); \
} while (0) } while (0)
@@ -612,8 +627,8 @@ TEST_BEGIN(test_arenas_bin_constants)
#define TEST_ARENAS_BIN_CONSTANT(t, name, expected) do { \ #define TEST_ARENAS_BIN_CONSTANT(t, name, expected) do { \
t name; \ t name; \
size_t sz = sizeof(t); \ size_t sz = sizeof(t); \
assert_d_eq(mallctl("arenas.bin.0."#name, &name, &sz, NULL, 0), \ assert_d_eq(mallctl("arenas.bin.0."#name, (void *)&name, &sz, \
0, "Unexpected mallctl() failure"); \ NULL, 0), 0, "Unexpected mallctl() failure"); \
assert_zu_eq(name, expected, "Incorrect "#name" size"); \ assert_zu_eq(name, expected, "Incorrect "#name" size"); \
} while (0) } while (0)
@@ -631,8 +646,8 @@ TEST_BEGIN(test_arenas_lrun_constants)
#define TEST_ARENAS_LRUN_CONSTANT(t, name, expected) do { \ #define TEST_ARENAS_LRUN_CONSTANT(t, name, expected) do { \
t name; \ t name; \
size_t sz = sizeof(t); \ size_t sz = sizeof(t); \
assert_d_eq(mallctl("arenas.lrun.0."#name, &name, &sz, NULL, \ assert_d_eq(mallctl("arenas.lrun.0."#name, (void *)&name, &sz, \
0), 0, "Unexpected mallctl() failure"); \ NULL, 0), 0, "Unexpected mallctl() failure"); \
assert_zu_eq(name, expected, "Incorrect "#name" size"); \ assert_zu_eq(name, expected, "Incorrect "#name" size"); \
} while (0) } while (0)
@@ -648,8 +663,8 @@ TEST_BEGIN(test_arenas_hchunk_constants)
#define TEST_ARENAS_HCHUNK_CONSTANT(t, name, expected) do { \ #define TEST_ARENAS_HCHUNK_CONSTANT(t, name, expected) do { \
t name; \ t name; \
size_t sz = sizeof(t); \ size_t sz = sizeof(t); \
assert_d_eq(mallctl("arenas.hchunk.0."#name, &name, &sz, NULL, \ assert_d_eq(mallctl("arenas.hchunk.0."#name, (void *)&name, \
0), 0, "Unexpected mallctl() failure"); \ &sz, NULL, 0), 0, "Unexpected mallctl() failure"); \
assert_zu_eq(name, expected, "Incorrect "#name" size"); \ assert_zu_eq(name, expected, "Incorrect "#name" size"); \
} while (0) } while (0)
@@ -664,12 +679,12 @@ TEST_BEGIN(test_arenas_extend)
unsigned narenas_before, arena, narenas_after; unsigned narenas_before, arena, narenas_after;
size_t sz = sizeof(unsigned); size_t sz = sizeof(unsigned);
assert_d_eq(mallctl("arenas.narenas", &narenas_before, &sz, NULL, 0), 0, assert_d_eq(mallctl("arenas.narenas", (void *)&narenas_before, &sz,
"Unexpected mallctl() failure"); NULL, 0), 0, "Unexpected mallctl() failure");
assert_d_eq(mallctl("arenas.extend", &arena, &sz, NULL, 0), 0, assert_d_eq(mallctl("arenas.extend", (void *)&arena, &sz, NULL, 0), 0,
"Unexpected mallctl() failure");
assert_d_eq(mallctl("arenas.narenas", &narenas_after, &sz, NULL, 0), 0,
"Unexpected mallctl() failure"); "Unexpected mallctl() failure");
assert_d_eq(mallctl("arenas.narenas", (void *)&narenas_after, &sz, NULL,
0), 0, "Unexpected mallctl() failure");
assert_u_eq(narenas_before+1, narenas_after, assert_u_eq(narenas_before+1, narenas_after,
"Unexpected number of arenas before versus after extension"); "Unexpected number of arenas before versus after extension");
@@ -683,8 +698,8 @@ TEST_BEGIN(test_stats_arenas)
#define TEST_STATS_ARENAS(t, name) do { \ #define TEST_STATS_ARENAS(t, name) do { \
t name; \ t name; \
size_t sz = sizeof(t); \ size_t sz = sizeof(t); \
assert_d_eq(mallctl("stats.arenas.0."#name, &name, &sz, NULL, \ assert_d_eq(mallctl("stats.arenas.0."#name, (void *)&name, &sz, \
0), 0, "Unexpected mallctl() failure"); \ NULL, 0), 0, "Unexpected mallctl() failure"); \
} while (0) } while (0)
TEST_STATS_ARENAS(unsigned, nthreads); TEST_STATS_ARENAS(unsigned, nthreads);

View File

@@ -5,6 +5,10 @@
#include <float.h> #include <float.h>
#ifdef __PGI
#undef INFINITY
#endif
#ifndef INFINITY #ifndef INFINITY
#define INFINITY (DBL_MAX + DBL_MAX) #define INFINITY (DBL_MAX + DBL_MAX)
#endif #endif

View File

@@ -176,6 +176,13 @@ TEST_BEGIN(test_nstime_divide)
} }
TEST_END TEST_END
TEST_BEGIN(test_nstime_monotonic)
{
nstime_monotonic();
}
TEST_END
TEST_BEGIN(test_nstime_update) TEST_BEGIN(test_nstime_update)
{ {
nstime_t nst; nstime_t nst;
@@ -198,7 +205,6 @@ TEST_BEGIN(test_nstime_update)
assert_d_eq(nstime_compare(&nst, &nst0), 0, assert_d_eq(nstime_compare(&nst, &nst0), 0,
"Time should not have been modified"); "Time should not have been modified");
} }
} }
TEST_END TEST_END
@@ -216,5 +222,6 @@ main(void)
test_nstime_imultiply, test_nstime_imultiply,
test_nstime_idivide, test_nstime_idivide,
test_nstime_divide, test_nstime_divide,
test_nstime_monotonic,
test_nstime_update)); test_nstime_update));
} }

Some files were not shown because too many files have changed in this diff Show More