diff options
Diffstat (limited to 'contrib')
134 files changed, 2852 insertions, 24110 deletions
diff --git a/contrib/jemalloc/INSTALL.md b/contrib/jemalloc/INSTALL.md index 9701364041c8..90da718d2b6a 100644 --- a/contrib/jemalloc/INSTALL.md +++ b/contrib/jemalloc/INSTALL.md @@ -1,4 +1,3 @@ -<<<<<<< HEAD Building and installing a packaged release of jemalloc can be as simple as typing the following while in the root directory of the source tree: @@ -423,427 +422,3 @@ can be used to view the html manual. The roff manual page can be formatted prior to installation via the following command: nroff -man -t doc/jemalloc.3 -||||||| dec341af7695 -======= -Building and installing a packaged release of jemalloc can be as simple as -typing the following while in the root directory of the source tree: - - ./configure - make - make install - -If building from unpackaged developer sources, the simplest command sequence -that might work is: - - ./autogen.sh - make dist - make - make install - -Note that documentation is not built by the default target because doing so -would create a dependency on xsltproc in packaged releases, hence the -requirement to either run 'make dist' or avoid installing docs via the various -install_* targets documented below. - - -## Advanced configuration - -The 'configure' script supports numerous options that allow control of which -functionality is enabled, where jemalloc is installed, etc. Optionally, pass -any of the following arguments (not a definitive list) to 'configure': - -* `--help` - - Print a definitive list of options. - -* `--prefix=<install-root-dir>` - - Set the base directory in which to install. For example: - - ./configure --prefix=/usr/local - - will cause files to be installed into /usr/local/include, /usr/local/lib, - and /usr/local/man. - -* `--with-version=(<major>.<minor>.<bugfix>-<nrev>-g<gid>|VERSION)` - - The VERSION file is mandatory for successful configuration, and the - following steps are taken to assure its presence: - 1) If --with-version=<major>.<minor>.<bugfix>-<nrev>-g<gid> is specified, - generate VERSION using the specified value. - 2) If --with-version is not specified in either form and the source - directory is inside a git repository, try to generate VERSION via 'git - describe' invocations that pattern-match release tags. - 3) If VERSION is missing, generate it with a bogus version: - 0.0.0-0-g0000000000000000000000000000000000000000 - - Note that --with-version=VERSION bypasses (1) and (2), which simplifies - VERSION configuration when embedding a jemalloc release into another - project's git repository. - -* `--with-rpath=<colon-separated-rpath>` - - Embed one or more library paths, so that libjemalloc can find the libraries - it is linked to. This works only on ELF-based systems. - -* `--with-mangling=<map>` - - Mangle public symbols specified in <map> which is a comma-separated list of - name:mangled pairs. - - For example, to use ld's --wrap option as an alternative method for - overriding libc's malloc implementation, specify something like: - - --with-mangling=malloc:__wrap_malloc,free:__wrap_free[...] - - Note that mangling happens prior to application of the prefix specified by - --with-jemalloc-prefix, and mangled symbols are then ignored when applying - the prefix. - -* `--with-jemalloc-prefix=<prefix>` - - Prefix all public APIs with <prefix>. For example, if <prefix> is - "prefix_", API changes like the following occur: - - malloc() --> prefix_malloc() - malloc_conf --> prefix_malloc_conf - /etc/malloc.conf --> /etc/prefix_malloc.conf - MALLOC_CONF --> PREFIX_MALLOC_CONF - - This makes it possible to use jemalloc at the same time as the system - allocator, or even to use multiple copies of jemalloc simultaneously. - - By default, the prefix is "", except on OS X, where it is "je_". On OS X, - jemalloc overlays the default malloc zone, but makes no attempt to actually - replace the "malloc", "calloc", etc. symbols. - -* `--without-export` - - Don't export public APIs. This can be useful when building jemalloc as a - static library, or to avoid exporting public APIs when using the zone - allocator on OSX. - -* `--with-private-namespace=<prefix>` - - Prefix all library-private APIs with <prefix>je_. For shared libraries, - symbol visibility mechanisms prevent these symbols from being exported, but - for static libraries, naming collisions are a real possibility. By - default, <prefix> is empty, which results in a symbol prefix of je_ . - -* `--with-install-suffix=<suffix>` - - Append <suffix> to the base name of all installed files, such that multiple - versions of jemalloc can coexist in the same installation directory. For - example, libjemalloc.so.0 becomes libjemalloc<suffix>.so.0. - -* `--with-malloc-conf=<malloc_conf>` - - Embed `<malloc_conf>` as a run-time options string that is processed prior to - the malloc_conf global variable, the /etc/malloc.conf symlink, and the - MALLOC_CONF environment variable. For example, to change the default decay - time to 30 seconds: - - --with-malloc-conf=decay_ms:30000 - -* `--enable-debug` - - Enable assertions and validation code. This incurs a substantial - performance hit, but is very useful during application development. - -* `--disable-stats` - - Disable statistics gathering functionality. See the "opt.stats_print" - option documentation for usage details. - -* `--enable-prof` - - Enable heap profiling and leak detection functionality. See the "opt.prof" - option documentation for usage details. When enabled, there are several - approaches to backtracing, and the configure script chooses the first one - in the following list that appears to function correctly: - - + libunwind (requires --enable-prof-libunwind) - + libgcc (unless --disable-prof-libgcc) - + gcc intrinsics (unless --disable-prof-gcc) - -* `--enable-prof-libunwind` - - Use the libunwind library (http://www.nongnu.org/libunwind/) for stack - backtracing. - -* `--disable-prof-libgcc` - - Disable the use of libgcc's backtracing functionality. - -* `--disable-prof-gcc` - - Disable the use of gcc intrinsics for backtracing. - -* `--with-static-libunwind=<libunwind.a>` - - Statically link against the specified libunwind.a rather than dynamically - linking with -lunwind. - -* `--disable-fill` - - Disable support for junk/zero filling of memory. See the "opt.junk" and - "opt.zero" option documentation for usage details. - -* `--disable-zone-allocator` - - Disable zone allocator for Darwin. This means jemalloc won't be hooked as - the default allocator on OSX/iOS. - -* `--enable-utrace` - - Enable utrace(2)-based allocation tracing. This feature is not broadly - portable (FreeBSD has it, but Linux and OS X do not). - -* `--enable-xmalloc` - - Enable support for optional immediate termination due to out-of-memory - errors, as is commonly implemented by "xmalloc" wrapper function for malloc. - See the "opt.xmalloc" option documentation for usage details. - -* `--enable-lazy-lock` - - Enable code that wraps pthread_create() to detect when an application - switches from single-threaded to multi-threaded mode, so that it can avoid - mutex locking/unlocking operations while in single-threaded mode. In - practice, this feature usually has little impact on performance unless - thread-specific caching is disabled. - -* `--disable-cache-oblivious` - - Disable cache-oblivious large allocation alignment for large allocation - requests with no alignment constraints. If this feature is disabled, all - large allocations are page-aligned as an implementation artifact, which can - severely harm CPU cache utilization. However, the cache-oblivious layout - comes at the cost of one extra page per large allocation, which in the - most extreme case increases physical memory usage for the 16 KiB size class - 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). - -* `--disable-cxx` - - Disable C++ integration. This will cause new and delete operator - implementations to be omitted. - -* `--with-xslroot=<path>` - - Specify where to find DocBook XSL stylesheets when building the - documentation. - -* `--with-lg-page=<lg-page>` - - Specify the base 2 log of the allocator page size, which must in turn be at - least as large as the system page size. By default the configure script - determines the host's page size and sets the allocator page size equal to - the system page size, so this option need not be specified unless the - system page size may change between configuration and execution, e.g. when - cross compiling. - -* `--with-lg-hugepage=<lg-hugepage>` - - Specify the base 2 log of the system huge page size. This option is useful - when cross compiling, or when overriding the default for systems that do - not explicitly support huge pages. - -* `--with-lg-quantum=<lg-quantum>` - - Specify the base 2 log of the minimum allocation alignment. jemalloc needs - to know the minimum alignment that meets the following C standard - requirement (quoted from the April 12, 2011 draft of the C11 standard): - - > The pointer returned if the allocation succeeds is suitably aligned so - that it may be assigned to a pointer to any type of object with a - fundamental alignment requirement and then used to access such an object - or an array of such objects in the space allocated [...] - - This setting is architecture-specific, and although jemalloc includes known - safe values for the most commonly used modern architectures, there is a - wrinkle related to GNU libc (glibc) that may impact your choice of - <lg-quantum>. On most modern architectures, this mandates 16-byte - alignment (<lg-quantum>=4), but the glibc developers chose not to meet this - requirement for performance reasons. An old discussion can be found at - <https://sourceware.org/bugzilla/show_bug.cgi?id=206> . Unlike glibc, - jemalloc does follow the C standard by default (caveat: jemalloc - technically cheats for size classes smaller than the quantum), but the fact - that Linux systems already work around this allocator noncompliance means - that it is generally safe in practice to let jemalloc's minimum alignment - follow glibc's lead. If you specify `--with-lg-quantum=3` during - configuration, jemalloc will provide additional size classes that are not - 16-byte-aligned (24, 40, and 56). - -* `--with-lg-vaddr=<lg-vaddr>` - - Specify the number of significant virtual address bits. By default, the - configure script attempts to detect virtual address size on those platforms - where it knows how, and picks a default otherwise. This option may be - useful when cross-compiling. - -* `--disable-initial-exec-tls` - - Disable the initial-exec TLS model for jemalloc's internal thread-local - storage (on those platforms that support explicit settings). This can allow - jemalloc to be dynamically loaded after program startup (e.g. using dlopen). - Note that in this case, there will be two malloc implementations operating - in the same process, which will almost certainly result in confusing runtime - crashes if pointers leak from one implementation to the other. - -* `--disable-libdl` - - Disable the usage of libdl, namely dlsym(3) which is required by the lazy - lock option. This can allow building static binaries. - -The following environment variables (not a definitive list) impact configure's -behavior: - -* `CFLAGS="?"` -* `CXXFLAGS="?"` - - Pass these flags to the C/C++ compiler. Any flags set by the configure - script 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_CXXFLAGS="?"` - - Append these flags to CFLAGS/CXXFLAGS, without passing them to the - compiler(s) during configuration. This makes it possible to add flags such - as -Werror, while allowing the configure script to determine what other - flags are appropriate for the specified configuration. - -* `CPPFLAGS="?"` - - Pass these flags to the C preprocessor. Note that CFLAGS is not passed to - 'cpp' when 'configure' is looking for include files, so you must use - CPPFLAGS instead if you need to help 'configure' find header files. - -* `LD_LIBRARY_PATH="?"` - - 'ld' uses this colon-separated list to find libraries. - -* `LDFLAGS="?"` - - Pass these flags when linking. - -* `PATH="?"` - - '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 - -To build only parts of jemalloc, use the following targets: - - build_lib_shared - build_lib_static - build_lib - build_doc_html - build_doc_man - build_doc - -To install only parts of jemalloc, use the following targets: - - install_bin - install_include - install_lib_shared - install_lib_static - install_lib_pc - install_lib - install_doc_html - install_doc_man - install_doc - -To clean up build results to varying degrees, use the following make targets: - - clean - distclean - relclean - - -## Advanced installation - -Optionally, define make variables when invoking make, including (not -exclusively): - -* `INCLUDEDIR="?"` - - Use this as the installation prefix for header files. - -* `LIBDIR="?"` - - Use this as the installation prefix for libraries. - -* `MANDIR="?"` - - Use this as the installation prefix for man pages. - -* `DESTDIR="?"` - - Prepend DESTDIR to INCLUDEDIR, LIBDIR, DATADIR, and MANDIR. This is useful - when installing to a different path than was specified via --prefix. - -* `CC="?"` - - Use this to invoke the C compiler. - -* `CFLAGS="?"` - - Pass these flags to the compiler. - -* `CPPFLAGS="?"` - - Pass these flags to the C preprocessor. - -* `LDFLAGS="?"` - - Pass these flags when linking. - -* `PATH="?"` - - Use this to search for programs used during configuration and building. - - -## Development - -If you intend to make non-trivial changes to jemalloc, use the 'autogen.sh' -script rather than 'configure'. This re-generates 'configure', enables -configuration dependency rules, and enables re-generation of automatically -generated source files. - -The build system supports using an object directory separate from the source -tree. For example, you can create an 'obj' directory, and from within that -directory, issue configuration and build commands: - - autoconf - mkdir obj - cd obj - ../configure --enable-autogen - make - - -## Documentation - -The manual page is generated in both html and roff formats. Any web browser -can be used to view the html manual. The roff manual page can be formatted -prior to installation via the following command: - - nroff -man -t doc/jemalloc.3 ->>>>>>> main diff --git a/contrib/jemalloc/Makefile.in b/contrib/jemalloc/Makefile.in index 121297702bcc..1193cd859c49 100644 --- a/contrib/jemalloc/Makefile.in +++ b/contrib/jemalloc/Makefile.in @@ -1,4 +1,3 @@ -<<<<<<< HEAD # Clear out all vpaths, then set just one (default vpath) for the main build # directory. vpath @@ -761,629 +760,3 @@ $(objroot)config.stamp : $(cfgoutputs_in) $(cfghdrs_in) $(srcroot)configure $(cfgoutputs_out) $(cfghdrs_out) : $(objroot)config.stamp @true endif -||||||| dec341af7695 -======= -# Clear out all vpaths, then set just one (default vpath) for the main build -# directory. -vpath -vpath % . - -# Clear the default suffixes, so that built-in rules are not used. -.SUFFIXES : - -SHELL := /bin/sh - -CC := @CC@ -CXX := @CXX@ - -# Configuration parameters. -DESTDIR = -BINDIR := $(DESTDIR)@BINDIR@ -INCLUDEDIR := $(DESTDIR)@INCLUDEDIR@ -LIBDIR := $(DESTDIR)@LIBDIR@ -DATADIR := $(DESTDIR)@DATADIR@ -MANDIR := $(DESTDIR)@MANDIR@ -srcroot := @srcroot@ -objroot := @objroot@ -abs_srcroot := @abs_srcroot@ -abs_objroot := @abs_objroot@ - -# Build parameters. -CPPFLAGS := @CPPFLAGS@ -I$(objroot)include -I$(srcroot)include -CONFIGURE_CFLAGS := @CONFIGURE_CFLAGS@ -SPECIFIED_CFLAGS := @SPECIFIED_CFLAGS@ -EXTRA_CFLAGS := @EXTRA_CFLAGS@ -CFLAGS := $(strip $(CONFIGURE_CFLAGS) $(SPECIFIED_CFLAGS) $(EXTRA_CFLAGS)) -CONFIGURE_CXXFLAGS := @CONFIGURE_CXXFLAGS@ -SPECIFIED_CXXFLAGS := @SPECIFIED_CXXFLAGS@ -EXTRA_CXXFLAGS := @EXTRA_CXXFLAGS@ -CXXFLAGS := $(strip $(CONFIGURE_CXXFLAGS) $(SPECIFIED_CXXFLAGS) $(EXTRA_CXXFLAGS)) -LDFLAGS := @LDFLAGS@ -EXTRA_LDFLAGS := @EXTRA_LDFLAGS@ -LIBS := @LIBS@ -RPATH_EXTRA := @RPATH_EXTRA@ -SO := @so@ -IMPORTLIB := @importlib@ -O := @o@ -A := @a@ -EXE := @exe@ -LIBPREFIX := @libprefix@ -REV := @rev@ -install_suffix := @install_suffix@ -ABI := @abi@ -XSLTPROC := @XSLTPROC@ -XSLROOT := @XSLROOT@ -AUTOCONF := @AUTOCONF@ -_RPATH = @RPATH@ -RPATH = $(if $(1),$(call _RPATH,$(1))) -cfghdrs_in := $(addprefix $(srcroot),@cfghdrs_in@) -cfghdrs_out := @cfghdrs_out@ -cfgoutputs_in := $(addprefix $(srcroot),@cfgoutputs_in@) -cfgoutputs_out := @cfgoutputs_out@ -enable_autogen := @enable_autogen@ -enable_doc := @enable_doc@ -enable_shared := @enable_shared@ -enable_static := @enable_static@ -enable_prof := @enable_prof@ -enable_zone_allocator := @enable_zone_allocator@ -enable_experimental_smallocx := @enable_experimental_smallocx@ -MALLOC_CONF := @JEMALLOC_CPREFIX@MALLOC_CONF -link_whole_archive := @link_whole_archive@ -DSO_LDFLAGS = @DSO_LDFLAGS@ -SOREV = @SOREV@ -PIC_CFLAGS = @PIC_CFLAGS@ -CTARGET = @CTARGET@ -LDTARGET = @LDTARGET@ -TEST_LD_MODE = @TEST_LD_MODE@ -MKLIB = @MKLIB@ -AR = @AR@ -ARFLAGS = @ARFLAGS@ -DUMP_SYMS = @DUMP_SYMS@ -AWK := @AWK@ -CC_MM = @CC_MM@ -LM := @LM@ -INSTALL = @INSTALL@ - -ifeq (macho, $(ABI)) -TEST_LIBRARY_PATH := DYLD_FALLBACK_LIBRARY_PATH="$(objroot)lib" -else -ifeq (pecoff, $(ABI)) -TEST_LIBRARY_PATH := PATH="$(PATH):$(objroot)lib" -else -TEST_LIBRARY_PATH := -endif -endif - -LIBJEMALLOC := $(LIBPREFIX)jemalloc$(install_suffix) - -# Lists of files. -BINS := $(objroot)bin/jemalloc-config $(objroot)bin/jemalloc.sh $(objroot)bin/jeprof -C_HDRS := $(objroot)include/jemalloc/jemalloc$(install_suffix).h -C_SRCS := $(srcroot)src/jemalloc.c \ - $(srcroot)src/arena.c \ - $(srcroot)src/background_thread.c \ - $(srcroot)src/base.c \ - $(srcroot)src/bin.c \ - $(srcroot)src/bitmap.c \ - $(srcroot)src/ckh.c \ - $(srcroot)src/ctl.c \ - $(srcroot)src/div.c \ - $(srcroot)src/extent.c \ - $(srcroot)src/extent_dss.c \ - $(srcroot)src/extent_mmap.c \ - $(srcroot)src/hash.c \ - $(srcroot)src/hook.c \ - $(srcroot)src/large.c \ - $(srcroot)src/log.c \ - $(srcroot)src/malloc_io.c \ - $(srcroot)src/mutex.c \ - $(srcroot)src/mutex_pool.c \ - $(srcroot)src/nstime.c \ - $(srcroot)src/pages.c \ - $(srcroot)src/prng.c \ - $(srcroot)src/prof.c \ - $(srcroot)src/rtree.c \ - $(srcroot)src/safety_check.c \ - $(srcroot)src/stats.c \ - $(srcroot)src/sc.c \ - $(srcroot)src/sz.c \ - $(srcroot)src/tcache.c \ - $(srcroot)src/test_hooks.c \ - $(srcroot)src/ticker.c \ - $(srcroot)src/tsd.c \ - $(srcroot)src/witness.c -ifeq ($(enable_zone_allocator), 1) -C_SRCS += $(srcroot)src/zone.c -endif -ifeq ($(IMPORTLIB),$(SO)) -STATIC_LIBS := $(objroot)lib/$(LIBJEMALLOC).$(A) -endif -ifdef PIC_CFLAGS -STATIC_LIBS += $(objroot)lib/$(LIBJEMALLOC)_pic.$(A) -else -STATIC_LIBS += $(objroot)lib/$(LIBJEMALLOC)_s.$(A) -endif -DSOS := $(objroot)lib/$(LIBJEMALLOC).$(SOREV) -ifneq ($(SOREV),$(SO)) -DSOS += $(objroot)lib/$(LIBJEMALLOC).$(SO) -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 -MAN3 := $(objroot)doc/jemalloc$(install_suffix).3 -DOCS_XML := $(objroot)doc/jemalloc$(install_suffix).xml -DOCS_HTML := $(DOCS_XML:$(objroot)%.xml=$(objroot)%.html) -DOCS_MAN3 := $(DOCS_XML:$(objroot)%.xml=$(objroot)%.3) -DOCS := $(DOCS_HTML) $(DOCS_MAN3) -C_TESTLIB_SRCS := $(srcroot)test/src/btalloc.c $(srcroot)test/src/btalloc_0.c \ - $(srcroot)test/src/btalloc_1.c $(srcroot)test/src/math.c \ - $(srcroot)test/src/mtx.c $(srcroot)test/src/mq.c \ - $(srcroot)test/src/SFMT.c $(srcroot)test/src/test.c \ - $(srcroot)test/src/thd.c $(srcroot)test/src/timer.c -ifeq (1, $(link_whole_archive)) -C_UTIL_INTEGRATION_SRCS := -C_UTIL_CPP_SRCS := -else -C_UTIL_INTEGRATION_SRCS := $(srcroot)src/nstime.c $(srcroot)src/malloc_io.c -C_UTIL_CPP_SRCS := $(srcroot)src/nstime.c $(srcroot)src/malloc_io.c -endif -TESTS_UNIT := \ - $(srcroot)test/unit/a0.c \ - $(srcroot)test/unit/arena_reset.c \ - $(srcroot)test/unit/atomic.c \ - $(srcroot)test/unit/background_thread.c \ - $(srcroot)test/unit/background_thread_enable.c \ - $(srcroot)test/unit/base.c \ - $(srcroot)test/unit/bitmap.c \ - $(srcroot)test/unit/bit_util.c \ - $(srcroot)test/unit/binshard.c \ - $(srcroot)test/unit/ckh.c \ - $(srcroot)test/unit/decay.c \ - $(srcroot)test/unit/div.c \ - $(srcroot)test/unit/emitter.c \ - $(srcroot)test/unit/extent_quantize.c \ - $(srcroot)test/unit/extent_util.c \ - $(srcroot)test/unit/fork.c \ - $(srcroot)test/unit/hash.c \ - $(srcroot)test/unit/hook.c \ - $(srcroot)test/unit/huge.c \ - $(srcroot)test/unit/junk.c \ - $(srcroot)test/unit/junk_alloc.c \ - $(srcroot)test/unit/junk_free.c \ - $(srcroot)test/unit/log.c \ - $(srcroot)test/unit/mallctl.c \ - $(srcroot)test/unit/malloc_io.c \ - $(srcroot)test/unit/math.c \ - $(srcroot)test/unit/mq.c \ - $(srcroot)test/unit/mtx.c \ - $(srcroot)test/unit/pack.c \ - $(srcroot)test/unit/pages.c \ - $(srcroot)test/unit/ph.c \ - $(srcroot)test/unit/prng.c \ - $(srcroot)test/unit/prof_accum.c \ - $(srcroot)test/unit/prof_active.c \ - $(srcroot)test/unit/prof_gdump.c \ - $(srcroot)test/unit/prof_idump.c \ - $(srcroot)test/unit/prof_log.c \ - $(srcroot)test/unit/prof_reset.c \ - $(srcroot)test/unit/prof_tctx.c \ - $(srcroot)test/unit/prof_thread_name.c \ - $(srcroot)test/unit/ql.c \ - $(srcroot)test/unit/qr.c \ - $(srcroot)test/unit/rb.c \ - $(srcroot)test/unit/retained.c \ - $(srcroot)test/unit/rtree.c \ - $(srcroot)test/unit/safety_check.c \ - $(srcroot)test/unit/seq.c \ - $(srcroot)test/unit/SFMT.c \ - $(srcroot)test/unit/sc.c \ - $(srcroot)test/unit/size_classes.c \ - $(srcroot)test/unit/slab.c \ - $(srcroot)test/unit/smoothstep.c \ - $(srcroot)test/unit/spin.c \ - $(srcroot)test/unit/stats.c \ - $(srcroot)test/unit/stats_print.c \ - $(srcroot)test/unit/test_hooks.c \ - $(srcroot)test/unit/ticker.c \ - $(srcroot)test/unit/nstime.c \ - $(srcroot)test/unit/tsd.c \ - $(srcroot)test/unit/witness.c \ - $(srcroot)test/unit/zero.c -ifeq (@enable_prof@, 1) -TESTS_UNIT += \ - $(srcroot)test/unit/arena_reset_prof.c -endif -TESTS_INTEGRATION := $(srcroot)test/integration/aligned_alloc.c \ - $(srcroot)test/integration/allocated.c \ - $(srcroot)test/integration/extent.c \ - $(srcroot)test/integration/malloc.c \ - $(srcroot)test/integration/mallocx.c \ - $(srcroot)test/integration/MALLOCX_ARENA.c \ - $(srcroot)test/integration/overflow.c \ - $(srcroot)test/integration/posix_memalign.c \ - $(srcroot)test/integration/rallocx.c \ - $(srcroot)test/integration/sdallocx.c \ - $(srcroot)test/integration/slab_sizes.c \ - $(srcroot)test/integration/thread_arena.c \ - $(srcroot)test/integration/thread_tcache_enabled.c \ - $(srcroot)test/integration/xallocx.c -ifeq (@enable_experimental_smallocx@, 1) -TESTS_INTEGRATION += \ - $(srcroot)test/integration/smallocx.c -endif -ifeq (@enable_cxx@, 1) -CPP_SRCS := $(srcroot)src/jemalloc_cpp.cpp -TESTS_INTEGRATION_CPP := $(srcroot)test/integration/cpp/basic.cpp -else -CPP_SRCS := -TESTS_INTEGRATION_CPP := -endif -TESTS_STRESS := $(srcroot)test/stress/microbench.c \ - $(srcroot)test/stress/hookbench.c - - -TESTS := $(TESTS_UNIT) $(TESTS_INTEGRATION) $(TESTS_INTEGRATION_CPP) $(TESTS_STRESS) - -PRIVATE_NAMESPACE_HDRS := $(objroot)include/jemalloc/internal/private_namespace.h $(objroot)include/jemalloc/internal/private_namespace_jet.h -PRIVATE_NAMESPACE_GEN_HDRS := $(PRIVATE_NAMESPACE_HDRS:%.h=%.gen.h) -C_SYM_OBJS := $(C_SRCS:$(srcroot)%.c=$(objroot)%.sym.$(O)) -C_SYMS := $(C_SRCS:$(srcroot)%.c=$(objroot)%.sym) -C_OBJS := $(C_SRCS:$(srcroot)%.c=$(objroot)%.$(O)) -CPP_OBJS := $(CPP_SRCS:$(srcroot)%.cpp=$(objroot)%.$(O)) -C_PIC_OBJS := $(C_SRCS:$(srcroot)%.c=$(objroot)%.pic.$(O)) -CPP_PIC_OBJS := $(CPP_SRCS:$(srcroot)%.cpp=$(objroot)%.pic.$(O)) -C_JET_SYM_OBJS := $(C_SRCS:$(srcroot)%.c=$(objroot)%.jet.sym.$(O)) -C_JET_SYMS := $(C_SRCS:$(srcroot)%.c=$(objroot)%.jet.sym) -C_JET_OBJS := $(C_SRCS:$(srcroot)%.c=$(objroot)%.jet.$(O)) -C_TESTLIB_UNIT_OBJS := $(C_TESTLIB_SRCS:$(srcroot)%.c=$(objroot)%.unit.$(O)) -C_TESTLIB_INTEGRATION_OBJS := $(C_TESTLIB_SRCS:$(srcroot)%.c=$(objroot)%.integration.$(O)) -C_UTIL_INTEGRATION_OBJS := $(C_UTIL_INTEGRATION_SRCS:$(srcroot)%.c=$(objroot)%.integration.$(O)) -C_TESTLIB_STRESS_OBJS := $(C_TESTLIB_SRCS:$(srcroot)%.c=$(objroot)%.stress.$(O)) -C_TESTLIB_OBJS := $(C_TESTLIB_UNIT_OBJS) $(C_TESTLIB_INTEGRATION_OBJS) $(C_UTIL_INTEGRATION_OBJS) $(C_TESTLIB_STRESS_OBJS) - -TESTS_UNIT_OBJS := $(TESTS_UNIT:$(srcroot)%.c=$(objroot)%.$(O)) -TESTS_INTEGRATION_OBJS := $(TESTS_INTEGRATION:$(srcroot)%.c=$(objroot)%.$(O)) -TESTS_INTEGRATION_CPP_OBJS := $(TESTS_INTEGRATION_CPP:$(srcroot)%.cpp=$(objroot)%.$(O)) -TESTS_STRESS_OBJS := $(TESTS_STRESS:$(srcroot)%.c=$(objroot)%.$(O)) -TESTS_OBJS := $(TESTS_UNIT_OBJS) $(TESTS_INTEGRATION_OBJS) $(TESTS_STRESS_OBJS) -TESTS_CPP_OBJS := $(TESTS_INTEGRATION_CPP_OBJS) - -.PHONY: all dist build_doc_html build_doc_man build_doc -.PHONY: install_bin install_include install_lib -.PHONY: install_doc_html install_doc_man install_doc install -.PHONY: tests check clean distclean relclean - -.SECONDARY : $(PRIVATE_NAMESPACE_GEN_HDRS) $(TESTS_OBJS) $(TESTS_CPP_OBJS) - -# Default target. -all: build_lib - -dist: build_doc - -$(objroot)doc/%.html : $(objroot)doc/%.xml $(srcroot)doc/stylesheet.xsl $(objroot)doc/html.xsl -ifneq ($(XSLROOT),) - $(XSLTPROC) -o $@ $(objroot)doc/html.xsl $< -else -ifeq ($(wildcard $(DOCS_HTML)),) - @echo "<p>Missing xsltproc. Doc not built.</p>" > $@ -endif - @echo "Missing xsltproc. "$@" not (re)built." -endif - -$(objroot)doc/%.3 : $(objroot)doc/%.xml $(srcroot)doc/stylesheet.xsl $(objroot)doc/manpages.xsl -ifneq ($(XSLROOT),) - $(XSLTPROC) -o $@ $(objroot)doc/manpages.xsl $< -else -ifeq ($(wildcard $(DOCS_MAN3)),) - @echo "Missing xsltproc. Doc not built." > $@ -endif - @echo "Missing xsltproc. "$@" not (re)built." -endif - -build_doc_html: $(DOCS_HTML) -build_doc_man: $(DOCS_MAN3) -build_doc: $(DOCS) - -# -# Include generated dependency files. -# -ifdef CC_MM --include $(C_SYM_OBJS:%.$(O)=%.d) --include $(C_OBJS:%.$(O)=%.d) --include $(CPP_OBJS:%.$(O)=%.d) --include $(C_PIC_OBJS:%.$(O)=%.d) --include $(CPP_PIC_OBJS:%.$(O)=%.d) --include $(C_JET_SYM_OBJS:%.$(O)=%.d) --include $(C_JET_OBJS:%.$(O)=%.d) --include $(C_TESTLIB_OBJS:%.$(O)=%.d) --include $(TESTS_OBJS:%.$(O)=%.d) --include $(TESTS_CPP_OBJS:%.$(O)=%.d) -endif - -$(C_SYM_OBJS): $(objroot)src/%.sym.$(O): $(srcroot)src/%.c -$(C_SYM_OBJS): CPPFLAGS += -DJEMALLOC_NO_PRIVATE_NAMESPACE -$(C_SYMS): $(objroot)src/%.sym: $(objroot)src/%.sym.$(O) -$(C_OBJS): $(objroot)src/%.$(O): $(srcroot)src/%.c -$(CPP_OBJS): $(objroot)src/%.$(O): $(srcroot)src/%.cpp -$(C_PIC_OBJS): $(objroot)src/%.pic.$(O): $(srcroot)src/%.c -$(C_PIC_OBJS): CFLAGS += $(PIC_CFLAGS) -$(CPP_PIC_OBJS): $(objroot)src/%.pic.$(O): $(srcroot)src/%.cpp -$(CPP_PIC_OBJS): CXXFLAGS += $(PIC_CFLAGS) -$(C_JET_SYM_OBJS): $(objroot)src/%.jet.sym.$(O): $(srcroot)src/%.c -$(C_JET_SYM_OBJS): CPPFLAGS += -DJEMALLOC_JET -DJEMALLOC_NO_PRIVATE_NAMESPACE -$(C_JET_SYMS): $(objroot)src/%.jet.sym: $(objroot)src/%.jet.sym.$(O) -$(C_JET_OBJS): $(objroot)src/%.jet.$(O): $(srcroot)src/%.c -$(C_JET_OBJS): CPPFLAGS += -DJEMALLOC_JET -$(C_TESTLIB_UNIT_OBJS): $(objroot)test/src/%.unit.$(O): $(srcroot)test/src/%.c -$(C_TESTLIB_UNIT_OBJS): CPPFLAGS += -DJEMALLOC_UNIT_TEST -$(C_TESTLIB_INTEGRATION_OBJS): $(objroot)test/src/%.integration.$(O): $(srcroot)test/src/%.c -$(C_TESTLIB_INTEGRATION_OBJS): CPPFLAGS += -DJEMALLOC_INTEGRATION_TEST -$(C_UTIL_INTEGRATION_OBJS): $(objroot)src/%.integration.$(O): $(srcroot)src/%.c -$(C_TESTLIB_STRESS_OBJS): $(objroot)test/src/%.stress.$(O): $(srcroot)test/src/%.c -$(C_TESTLIB_STRESS_OBJS): CPPFLAGS += -DJEMALLOC_STRESS_TEST -DJEMALLOC_STRESS_TESTLIB -$(C_TESTLIB_OBJS): CPPFLAGS += -I$(srcroot)test/include -I$(objroot)test/include -$(TESTS_UNIT_OBJS): CPPFLAGS += -DJEMALLOC_UNIT_TEST -$(TESTS_INTEGRATION_OBJS): CPPFLAGS += -DJEMALLOC_INTEGRATION_TEST -$(TESTS_INTEGRATION_CPP_OBJS): CPPFLAGS += -DJEMALLOC_INTEGRATION_CPP_TEST -$(TESTS_STRESS_OBJS): CPPFLAGS += -DJEMALLOC_STRESS_TEST -$(TESTS_OBJS): $(objroot)test/%.$(O): $(srcroot)test/%.c -$(TESTS_CPP_OBJS): $(objroot)test/%.$(O): $(srcroot)test/%.cpp -$(TESTS_OBJS): CPPFLAGS += -I$(srcroot)test/include -I$(objroot)test/include -$(TESTS_CPP_OBJS): CPPFLAGS += -I$(srcroot)test/include -I$(objroot)test/include -ifneq ($(IMPORTLIB),$(SO)) -$(CPP_OBJS) $(C_SYM_OBJS) $(C_OBJS) $(C_JET_SYM_OBJS) $(C_JET_OBJS): CPPFLAGS += -DDLLEXPORT -endif - -# Dependencies. -ifndef CC_MM -HEADER_DIRS = $(srcroot)include/jemalloc/internal \ - $(objroot)include/jemalloc $(objroot)include/jemalloc/internal -HEADERS = $(filter-out $(PRIVATE_NAMESPACE_HDRS),$(wildcard $(foreach dir,$(HEADER_DIRS),$(dir)/*.h))) -$(C_SYM_OBJS) $(C_OBJS) $(CPP_OBJS) $(C_PIC_OBJS) $(CPP_PIC_OBJS) $(C_JET_SYM_OBJS) $(C_JET_OBJS) $(C_TESTLIB_OBJS) $(TESTS_OBJS) $(TESTS_CPP_OBJS): $(HEADERS) -$(TESTS_OBJS) $(TESTS_CPP_OBJS): $(objroot)test/include/test/jemalloc_test.h -endif - -$(C_OBJS) $(CPP_OBJS) $(C_PIC_OBJS) $(CPP_PIC_OBJS) $(C_TESTLIB_INTEGRATION_OBJS) $(C_UTIL_INTEGRATION_OBJS) $(TESTS_INTEGRATION_OBJS) $(TESTS_INTEGRATION_CPP_OBJS): $(objroot)include/jemalloc/internal/private_namespace.h -$(C_JET_OBJS) $(C_TESTLIB_UNIT_OBJS) $(C_TESTLIB_STRESS_OBJS) $(TESTS_UNIT_OBJS) $(TESTS_STRESS_OBJS): $(objroot)include/jemalloc/internal/private_namespace_jet.h - -$(C_SYM_OBJS) $(C_OBJS) $(C_PIC_OBJS) $(C_JET_SYM_OBJS) $(C_JET_OBJS) $(C_TESTLIB_OBJS) $(TESTS_OBJS): %.$(O): - @mkdir -p $(@D) - $(CC) $(CFLAGS) -c $(CPPFLAGS) $(CTARGET) $< -ifdef CC_MM - @$(CC) -MM $(CPPFLAGS) -MT $@ -o $(@:%.$(O)=%.d) $< -endif - -$(C_SYMS): %.sym: - @mkdir -p $(@D) - $(DUMP_SYMS) $< | $(AWK) -f $(objroot)include/jemalloc/internal/private_symbols.awk > $@ - -$(C_JET_SYMS): %.sym: - @mkdir -p $(@D) - $(DUMP_SYMS) $< | $(AWK) -f $(objroot)include/jemalloc/internal/private_symbols_jet.awk > $@ - -$(objroot)include/jemalloc/internal/private_namespace.gen.h: $(C_SYMS) - $(SHELL) $(srcroot)include/jemalloc/internal/private_namespace.sh $^ > $@ - -$(objroot)include/jemalloc/internal/private_namespace_jet.gen.h: $(C_JET_SYMS) - $(SHELL) $(srcroot)include/jemalloc/internal/private_namespace.sh $^ > $@ - -%.h: %.gen.h - @if ! `cmp -s $< $@` ; then echo "cp $< $<"; cp $< $@ ; fi - -$(CPP_OBJS) $(CPP_PIC_OBJS) $(TESTS_CPP_OBJS): %.$(O): - @mkdir -p $(@D) - $(CXX) $(CXXFLAGS) -c $(CPPFLAGS) $(CTARGET) $< -ifdef CC_MM - @$(CXX) -MM $(CPPFLAGS) -MT $@ -o $(@:%.$(O)=%.d) $< -endif - -ifneq ($(SOREV),$(SO)) -%.$(SO) : %.$(SOREV) - @mkdir -p $(@D) - ln -sf $(<F) $@ -endif - -$(objroot)lib/$(LIBJEMALLOC).$(SOREV) : $(if $(PIC_CFLAGS),$(C_PIC_OBJS),$(C_OBJS)) $(if $(PIC_CFLAGS),$(CPP_PIC_OBJS),$(CPP_OBJS)) - @mkdir -p $(@D) - $(CC) $(DSO_LDFLAGS) $(call RPATH,$(RPATH_EXTRA)) $(LDTARGET) $+ $(LDFLAGS) $(LIBS) $(EXTRA_LDFLAGS) - -$(objroot)lib/$(LIBJEMALLOC)_pic.$(A) : $(C_PIC_OBJS) $(CPP_PIC_OBJS) -$(objroot)lib/$(LIBJEMALLOC).$(A) : $(C_OBJS) $(CPP_OBJS) -$(objroot)lib/$(LIBJEMALLOC)_s.$(A) : $(C_OBJS) $(CPP_OBJS) - -$(STATIC_LIBS): - @mkdir -p $(@D) - $(AR) $(ARFLAGS)@AROUT@ $+ - -$(objroot)test/unit/%$(EXE): $(objroot)test/unit/%.$(O) $(C_JET_OBJS) $(C_TESTLIB_UNIT_OBJS) - @mkdir -p $(@D) - $(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) - @mkdir -p $(@D) - $(CC) $(TEST_LD_MODE) $(LDTARGET) $(filter %.$(O),$^) $(call RPATH,$(objroot)lib) $(LJEMALLOC) $(LDFLAGS) $(filter-out -lm,$(filter -lrt -pthread -lstdc++,$(LIBS))) $(LM) $(EXTRA_LDFLAGS) - -$(objroot)test/integration/cpp/%$(EXE): $(objroot)test/integration/cpp/%.$(O) $(C_TESTLIB_INTEGRATION_OBJS) $(C_UTIL_INTEGRATION_OBJS) $(objroot)lib/$(LIBJEMALLOC).$(IMPORTLIB) - @mkdir -p $(@D) - $(CXX) $(LDTARGET) $(filter %.$(O),$^) $(call RPATH,$(objroot)lib) $(objroot)lib/$(LIBJEMALLOC).$(IMPORTLIB) $(LDFLAGS) $(filter-out -lm,$(LIBS)) -lm $(EXTRA_LDFLAGS) - -$(objroot)test/stress/%$(EXE): $(objroot)test/stress/%.$(O) $(C_JET_OBJS) $(C_TESTLIB_STRESS_OBJS) $(objroot)lib/$(LIBJEMALLOC).$(IMPORTLIB) - @mkdir -p $(@D) - $(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_static: $(STATIC_LIBS) -ifeq ($(enable_shared), 1) -build_lib: build_lib_shared -endif -ifeq ($(enable_static), 1) -build_lib: build_lib_static -endif - -install_bin: - $(INSTALL) -d $(BINDIR) - @for b in $(BINS); do \ - echo "$(INSTALL) -m 755 $$b $(BINDIR)"; \ - $(INSTALL) -m 755 $$b $(BINDIR); \ -done - -install_include: - $(INSTALL) -d $(INCLUDEDIR)/jemalloc - @for h in $(C_HDRS); do \ - echo "$(INSTALL) -m 644 $$h $(INCLUDEDIR)/jemalloc"; \ - $(INSTALL) -m 644 $$h $(INCLUDEDIR)/jemalloc; \ -done - -install_lib_shared: $(DSOS) - $(INSTALL) -d $(LIBDIR) - $(INSTALL) -m 755 $(objroot)lib/$(LIBJEMALLOC).$(SOREV) $(LIBDIR) -ifneq ($(SOREV),$(SO)) - ln -sf $(LIBJEMALLOC).$(SOREV) $(LIBDIR)/$(LIBJEMALLOC).$(SO) -endif - -install_lib_static: $(STATIC_LIBS) - $(INSTALL) -d $(LIBDIR) - @for l in $(STATIC_LIBS); do \ - echo "$(INSTALL) -m 755 $$l $(LIBDIR)"; \ - $(INSTALL) -m 755 $$l $(LIBDIR); \ -done - -install_lib_pc: $(PC) - $(INSTALL) -d $(LIBDIR)/pkgconfig - @for l in $(PC); do \ - echo "$(INSTALL) -m 644 $$l $(LIBDIR)/pkgconfig"; \ - $(INSTALL) -m 644 $$l $(LIBDIR)/pkgconfig; \ -done - -ifeq ($(enable_shared), 1) -install_lib: install_lib_shared -endif -ifeq ($(enable_static), 1) -install_lib: install_lib_static -endif -install_lib: install_lib_pc - -install_doc_html: - $(INSTALL) -d $(DATADIR)/doc/jemalloc$(install_suffix) - @for d in $(DOCS_HTML); do \ - echo "$(INSTALL) -m 644 $$d $(DATADIR)/doc/jemalloc$(install_suffix)"; \ - $(INSTALL) -m 644 $$d $(DATADIR)/doc/jemalloc$(install_suffix); \ -done - -install_doc_man: - $(INSTALL) -d $(MANDIR)/man3 - @for d in $(DOCS_MAN3); do \ - echo "$(INSTALL) -m 644 $$d $(MANDIR)/man3"; \ - $(INSTALL) -m 644 $$d $(MANDIR)/man3; \ -done - -install_doc: build_doc install_doc_html install_doc_man - -install: install_bin install_include install_lib - -ifeq ($(enable_doc), 1) -install: install_doc -endif - -tests_unit: $(TESTS_UNIT:$(srcroot)%.c=$(objroot)%$(EXE)) -tests_integration: $(TESTS_INTEGRATION:$(srcroot)%.c=$(objroot)%$(EXE)) $(TESTS_INTEGRATION_CPP:$(srcroot)%.cpp=$(objroot)%$(EXE)) -tests_stress: $(TESTS_STRESS:$(srcroot)%.c=$(objroot)%$(EXE)) -tests: tests_unit tests_integration tests_stress - -check_unit_dir: - @mkdir -p $(objroot)test/unit -check_integration_dir: - @mkdir -p $(objroot)test/integration -stress_dir: - @mkdir -p $(objroot)test/stress -check_dir: check_unit_dir check_integration_dir - -check_unit: tests_unit check_unit_dir - $(SHELL) $(objroot)test/test.sh $(TESTS_UNIT:$(srcroot)%.c=$(objroot)%) -check_integration_prof: tests_integration check_integration_dir -ifeq ($(enable_prof), 1) - $(MALLOC_CONF)="prof:true" $(SHELL) $(objroot)test/test.sh $(TESTS_INTEGRATION:$(srcroot)%.c=$(objroot)%) $(TESTS_INTEGRATION_CPP:$(srcroot)%.cpp=$(objroot)%) - $(MALLOC_CONF)="prof:true,prof_active:false" $(SHELL) $(objroot)test/test.sh $(TESTS_INTEGRATION:$(srcroot)%.c=$(objroot)%) $(TESTS_INTEGRATION_CPP:$(srcroot)%.cpp=$(objroot)%) -endif -check_integration_decay: tests_integration check_integration_dir - $(MALLOC_CONF)="dirty_decay_ms:-1,muzzy_decay_ms:-1" $(SHELL) $(objroot)test/test.sh $(TESTS_INTEGRATION:$(srcroot)%.c=$(objroot)%) $(TESTS_INTEGRATION_CPP:$(srcroot)%.cpp=$(objroot)%) - $(MALLOC_CONF)="dirty_decay_ms:0,muzzy_decay_ms:0" $(SHELL) $(objroot)test/test.sh $(TESTS_INTEGRATION:$(srcroot)%.c=$(objroot)%) $(TESTS_INTEGRATION_CPP:$(srcroot)%.cpp=$(objroot)%) -check_integration: tests_integration check_integration_dir - $(SHELL) $(objroot)test/test.sh $(TESTS_INTEGRATION:$(srcroot)%.c=$(objroot)%) $(TESTS_INTEGRATION_CPP:$(srcroot)%.cpp=$(objroot)%) -stress: tests_stress stress_dir - $(SHELL) $(objroot)test/test.sh $(TESTS_STRESS:$(srcroot)%.c=$(objroot)%) -check: check_unit check_integration check_integration_decay check_integration_prof - -clean: - rm -f $(PRIVATE_NAMESPACE_HDRS) - rm -f $(PRIVATE_NAMESPACE_GEN_HDRS) - rm -f $(C_SYM_OBJS) - rm -f $(C_SYMS) - rm -f $(C_OBJS) - rm -f $(CPP_OBJS) - rm -f $(C_PIC_OBJS) - rm -f $(CPP_PIC_OBJS) - rm -f $(C_JET_SYM_OBJS) - rm -f $(C_JET_SYMS) - rm -f $(C_JET_OBJS) - rm -f $(C_TESTLIB_OBJS) - rm -f $(C_SYM_OBJS:%.$(O)=%.d) - rm -f $(C_OBJS:%.$(O)=%.d) - rm -f $(CPP_OBJS:%.$(O)=%.d) - rm -f $(C_PIC_OBJS:%.$(O)=%.d) - rm -f $(CPP_PIC_OBJS:%.$(O)=%.d) - rm -f $(C_JET_SYM_OBJS:%.$(O)=%.d) - rm -f $(C_JET_OBJS:%.$(O)=%.d) - rm -f $(C_TESTLIB_OBJS:%.$(O)=%.d) - rm -f $(TESTS_OBJS:%.$(O)=%$(EXE)) - rm -f $(TESTS_OBJS) - rm -f $(TESTS_OBJS:%.$(O)=%.d) - rm -f $(TESTS_OBJS:%.$(O)=%.out) - rm -f $(TESTS_CPP_OBJS:%.$(O)=%$(EXE)) - rm -f $(TESTS_CPP_OBJS) - rm -f $(TESTS_CPP_OBJS:%.$(O)=%.d) - rm -f $(TESTS_CPP_OBJS:%.$(O)=%.out) - rm -f $(DSOS) $(STATIC_LIBS) - -distclean: clean - rm -f $(objroot)bin/jemalloc-config - rm -f $(objroot)bin/jemalloc.sh - rm -f $(objroot)bin/jeprof - rm -f $(objroot)config.log - rm -f $(objroot)config.status - rm -f $(objroot)config.stamp - rm -f $(cfghdrs_out) - rm -f $(cfgoutputs_out) - -relclean: distclean - rm -f $(objroot)configure - rm -f $(objroot)VERSION - rm -f $(DOCS_HTML) - rm -f $(DOCS_MAN3) - -#=============================================================================== -# Re-configuration rules. - -ifeq ($(enable_autogen), 1) -$(srcroot)configure : $(srcroot)configure.ac - cd ./$(srcroot) && $(AUTOCONF) - -$(objroot)config.status : $(srcroot)configure - ./$(objroot)config.status --recheck - -$(srcroot)config.stamp.in : $(srcroot)configure.ac - echo stamp > $(srcroot)config.stamp.in - -$(objroot)config.stamp : $(cfgoutputs_in) $(cfghdrs_in) $(srcroot)configure - ./$(objroot)config.status - @touch $@ - -# There must be some action in order for make to re-read Makefile when it is -# out of date. -$(cfgoutputs_out) $(cfghdrs_out) : $(objroot)config.stamp - @true -endif ->>>>>>> main diff --git a/contrib/jemalloc/TUNING.md b/contrib/jemalloc/TUNING.md index 500541dd52d0..e96399d7c9b8 100644 --- a/contrib/jemalloc/TUNING.md +++ b/contrib/jemalloc/TUNING.md @@ -1,4 +1,3 @@ -<<<<<<< HEAD This document summarizes the common approaches for performance fine tuning with jemalloc (as of 5.3.0). The default configuration of jemalloc tends to work reasonably well in practice, and most applications should not have to tune any @@ -128,135 +127,3 @@ improve application performance with jemalloc. access / allocation patterns. Threads with heavy workloads often benefit from explicit binding, e.g. binding very active threads to dedicated arenas may reduce contention at the allocator level. -||||||| dec341af7695 -======= -This document summarizes the common approaches for performance fine tuning with -jemalloc (as of 5.1.0). The default configuration of jemalloc tends to work -reasonably well in practice, and most applications should not have to tune any -options. However, in order to cover a wide range of applications and avoid -pathological cases, the default setting is sometimes kept conservative and -suboptimal, even for many common workloads. When jemalloc is properly tuned for -a specific application / workload, it is common to improve system level metrics -by a few percent, or make favorable trade-offs. - - -## Notable runtime options for performance tuning - -Runtime options can be set via -[malloc_conf](http://jemalloc.net/jemalloc.3.html#tuning). - -* [background_thread](http://jemalloc.net/jemalloc.3.html#background_thread) - - Enabling jemalloc background threads generally improves the tail latency for - application threads, since unused memory purging is shifted to the dedicated - background threads. In addition, unintended purging delay caused by - application inactivity is avoided with background threads. - - Suggested: `background_thread:true` when jemalloc managed threads can be - allowed. - -* [metadata_thp](http://jemalloc.net/jemalloc.3.html#opt.metadata_thp) - - Allowing jemalloc to utilize transparent huge pages for its internal - metadata usually reduces TLB misses significantly, especially for programs - with large memory footprint and frequent allocation / deallocation - activities. Metadata memory usage may increase due to the use of huge - pages. - - Suggested for allocation intensive programs: `metadata_thp:auto` or - `metadata_thp:always`, which is expected to improve CPU utilization at a - small memory cost. - -* [dirty_decay_ms](http://jemalloc.net/jemalloc.3.html#opt.dirty_decay_ms) and - [muzzy_decay_ms](http://jemalloc.net/jemalloc.3.html#opt.muzzy_decay_ms) - - Decay time determines how fast jemalloc returns unused pages back to the - operating system, and therefore provides a fairly straightforward trade-off - between CPU and memory usage. Shorter decay time purges unused pages faster - to reduces memory usage (usually at the cost of more CPU cycles spent on - purging), and vice versa. - - Suggested: tune the values based on the desired trade-offs. - -* [narenas](http://jemalloc.net/jemalloc.3.html#opt.narenas) - - By default jemalloc uses multiple arenas to reduce internal lock contention. - However high arena count may also increase overall memory fragmentation, - since arenas manage memory independently. When high degree of parallelism - is not expected at the allocator level, lower number of arenas often - improves memory usage. - - Suggested: if low parallelism is expected, try lower arena count while - monitoring CPU and memory usage. - -* [percpu_arena](http://jemalloc.net/jemalloc.3.html#opt.percpu_arena) - - Enable dynamic thread to arena association based on running CPU. This has - the potential to improve locality, e.g. when thread to CPU affinity is - present. - - Suggested: try `percpu_arena:percpu` or `percpu_arena:phycpu` if - thread migration between processors is expected to be infrequent. - -Examples: - -* High resource consumption application, prioritizing CPU utilization: - - `background_thread:true,metadata_thp:auto` combined with relaxed decay time - (increased `dirty_decay_ms` and / or `muzzy_decay_ms`, - e.g. `dirty_decay_ms:30000,muzzy_decay_ms:30000`). - -* High resource consumption application, prioritizing memory usage: - - `background_thread:true` combined with shorter decay time (decreased - `dirty_decay_ms` and / or `muzzy_decay_ms`, - e.g. `dirty_decay_ms:5000,muzzy_decay_ms:5000`), and lower arena count - (e.g. number of CPUs). - -* Low resource consumption application: - - `narenas:1,lg_tcache_max:13` combined with shorter decay time (decreased - `dirty_decay_ms` and / or `muzzy_decay_ms`,e.g. - `dirty_decay_ms:1000,muzzy_decay_ms:0`). - -* Extremely conservative -- minimize memory usage at all costs, only suitable when -allocation activity is very rare: - - `narenas:1,tcache:false,dirty_decay_ms:0,muzzy_decay_ms:0` - -Note that it is recommended to combine the options with `abort_conf:true` which -aborts immediately on illegal options. - -## Beyond runtime options - -In addition to the runtime options, there are a number of programmatic ways to -improve application performance with jemalloc. - -* [Explicit arenas](http://jemalloc.net/jemalloc.3.html#arenas.create) - - Manually created arenas can help performance in various ways, e.g. by - managing locality and contention for specific usages. For example, - applications can explicitly allocate frequently accessed objects from a - dedicated arena with - [mallocx()](http://jemalloc.net/jemalloc.3.html#MALLOCX_ARENA) to improve - locality. In addition, explicit arenas often benefit from individually - tuned options, e.g. relaxed [decay - time](http://jemalloc.net/jemalloc.3.html#arena.i.dirty_decay_ms) if - frequent reuse is expected. - -* [Extent hooks](http://jemalloc.net/jemalloc.3.html#arena.i.extent_hooks) - - Extent hooks allow customization for managing underlying memory. One use - case for performance purpose is to utilize huge pages -- for example, - [HHVM](https://github.com/facebook/hhvm/blob/master/hphp/util/alloc.cpp) - uses explicit arenas with customized extent hooks to manage 1GB huge pages - for frequently accessed data, which reduces TLB misses significantly. - -* [Explicit thread-to-arena - binding](http://jemalloc.net/jemalloc.3.html#thread.arena) - - It is common for some threads in an application to have different memory - access / allocation patterns. Threads with heavy workloads often benefit - from explicit binding, e.g. binding very active threads to dedicated arenas - may reduce contention at the allocator level. ->>>>>>> main diff --git a/contrib/jemalloc/bin/jeprof.in b/contrib/jemalloc/bin/jeprof.in index dc2c3ea877b8..dbf6252b921e 100644 --- a/contrib/jemalloc/bin/jeprof.in +++ b/contrib/jemalloc/bin/jeprof.in @@ -1,4 +1,3 @@ -<<<<<<< HEAD #! /usr/bin/env perl # Copyright (c) 1998-2007, Google Inc. @@ -5722,5631 +5721,3 @@ sub RunUnitTests { } exit ($error_count); } -||||||| dec341af7695 -======= -#! /usr/bin/env perl - -# Copyright (c) 1998-2007, Google Inc. -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are -# met: -# -# * Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# * Redistributions in binary form must reproduce the above -# copyright notice, this list of conditions and the following disclaimer -# in the documentation and/or other materials provided with the -# distribution. -# * Neither the name of Google Inc. nor the names of its -# contributors may be used to endorse or promote products derived from -# this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -# --- -# Program for printing the profile generated by common/profiler.cc, -# or by the heap profiler (common/debugallocation.cc) -# -# The profile contains a sequence of entries of the form: -# <count> <stack trace> -# This program parses the profile, and generates user-readable -# output. -# -# Examples: -# -# % tools/jeprof "program" "profile" -# Enters "interactive" mode -# -# % tools/jeprof --text "program" "profile" -# Generates one line per procedure -# -# % tools/jeprof --gv "program" "profile" -# Generates annotated call-graph and displays via "gv" -# -# % tools/jeprof --gv --focus=Mutex "program" "profile" -# Restrict to code paths that involve an entry that matches "Mutex" -# -# % tools/jeprof --gv --focus=Mutex --ignore=string "program" "profile" -# Restrict to code paths that involve an entry that matches "Mutex" -# and does not match "string" -# -# % tools/jeprof --list=IBF_CheckDocid "program" "profile" -# Generates disassembly listing of all routines with at least one -# sample that match the --list=<regexp> pattern. The listing is -# annotated with the flat and cumulative sample counts at each line. -# -# % tools/jeprof --disasm=IBF_CheckDocid "program" "profile" -# Generates disassembly listing of all routines with at least one -# sample that match the --disasm=<regexp> pattern. The listing is -# annotated with the flat and cumulative sample counts at each PC value. -# -# TODO: Use color to indicate files? - -use strict; -use warnings; -use Getopt::Long; -use Cwd; - -my $JEPROF_VERSION = "@jemalloc_version@"; -my $PPROF_VERSION = "2.0"; - -# These are the object tools we use which can come from a -# user-specified location using --tools, from the JEPROF_TOOLS -# environment variable, or from the environment. -my %obj_tool_map = ( - "objdump" => "objdump", - "nm" => "nm", - "addr2line" => "addr2line", - "c++filt" => "c++filt", - ## ConfigureObjTools may add architecture-specific entries: - #"nm_pdb" => "nm-pdb", # for reading windows (PDB-format) executables - #"addr2line_pdb" => "addr2line-pdb", # ditto - #"otool" => "otool", # equivalent of objdump on OS X -); -# NOTE: these are lists, so you can put in commandline flags if you want. -my @DOT = ("dot"); # leave non-absolute, since it may be in /usr/local -my @GV = ("gv"); -my @EVINCE = ("evince"); # could also be xpdf or perhaps acroread -my @KCACHEGRIND = ("kcachegrind"); -my @PS2PDF = ("ps2pdf"); -# These are used for dynamic profiles -my @URL_FETCHER = ("curl", "-s", "--fail"); - -# These are the web pages that servers need to support for dynamic profiles -my $HEAP_PAGE = "/pprof/heap"; -my $PROFILE_PAGE = "/pprof/profile"; # must support cgi-param "?seconds=#" -my $PMUPROFILE_PAGE = "/pprof/pmuprofile(?:\\?.*)?"; # must support cgi-param - # ?seconds=#&event=x&period=n -my $GROWTH_PAGE = "/pprof/growth"; -my $CONTENTION_PAGE = "/pprof/contention"; -my $WALL_PAGE = "/pprof/wall(?:\\?.*)?"; # accepts options like namefilter -my $FILTEREDPROFILE_PAGE = "/pprof/filteredprofile(?:\\?.*)?"; -my $CENSUSPROFILE_PAGE = "/pprof/censusprofile(?:\\?.*)?"; # must support cgi-param - # "?seconds=#", - # "?tags_regexp=#" and - # "?type=#". -my $SYMBOL_PAGE = "/pprof/symbol"; # must support symbol lookup via POST -my $PROGRAM_NAME_PAGE = "/pprof/cmdline"; - -# These are the web pages that can be named on the command line. -# All the alternatives must begin with /. -my $PROFILES = "($HEAP_PAGE|$PROFILE_PAGE|$PMUPROFILE_PAGE|" . - "$GROWTH_PAGE|$CONTENTION_PAGE|$WALL_PAGE|" . - "$FILTEREDPROFILE_PAGE|$CENSUSPROFILE_PAGE)"; - -# default binary name -my $UNKNOWN_BINARY = "(unknown)"; - -# There is a pervasive dependency on the length (in hex characters, -# i.e., nibbles) of an address, distinguishing between 32-bit and -# 64-bit profiles. To err on the safe size, default to 64-bit here: -my $address_length = 16; - -my $dev_null = "/dev/null"; -if (! -e $dev_null && $^O =~ /MSWin/) { # $^O is the OS perl was built for - $dev_null = "nul"; -} - -# A list of paths to search for shared object files -my @prefix_list = (); - -# Special routine name that should not have any symbols. -# Used as separator to parse "addr2line -i" output. -my $sep_symbol = '_fini'; -my $sep_address = undef; - -##### Argument parsing ##### - -sub usage_string { - return <<EOF; -Usage: -jeprof [options] <program> <profiles> - <profiles> is a space separated list of profile names. -jeprof [options] <symbolized-profiles> - <symbolized-profiles> is a list of profile files where each file contains - the necessary symbol mappings as well as profile data (likely generated - with --raw). -jeprof [options] <profile> - <profile> is a remote form. Symbols are obtained from host:port$SYMBOL_PAGE - - Each name can be: - /path/to/profile - a path to a profile file - host:port[/<service>] - a location of a service to get profile from - - The /<service> can be $HEAP_PAGE, $PROFILE_PAGE, /pprof/pmuprofile, - $GROWTH_PAGE, $CONTENTION_PAGE, /pprof/wall, - $CENSUSPROFILE_PAGE, or /pprof/filteredprofile. - For instance: - jeprof http://myserver.com:80$HEAP_PAGE - If /<service> is omitted, the service defaults to $PROFILE_PAGE (cpu profiling). -jeprof --symbols <program> - Maps addresses to symbol names. In this mode, stdin should be a - list of library mappings, in the same format as is found in the heap- - and cpu-profile files (this loosely matches that of /proc/self/maps - on linux), followed by a list of hex addresses to map, one per line. - - For more help with querying remote servers, including how to add the - necessary server-side support code, see this filename (or one like it): - - /usr/doc/gperftools-$PPROF_VERSION/pprof_remote_servers.html - -Options: - --cum Sort by cumulative data - --base=<base> Subtract <base> from <profile> before display - --interactive Run in interactive mode (interactive "help" gives help) [default] - --seconds=<n> Length of time for dynamic profiles [default=30 secs] - --add_lib=<file> Read additional symbols and line info from the given library - --lib_prefix=<dir> Comma separated list of library path prefixes - -Reporting Granularity: - --addresses Report at address level - --lines Report at source line level - --functions Report at function level [default] - --files Report at source file level - -Output type: - --text Generate text report - --callgrind Generate callgrind format to stdout - --gv Generate Postscript and display - --evince Generate PDF and display - --web Generate SVG and display - --list=<regexp> Generate source listing of matching routines - --disasm=<regexp> Generate disassembly of matching routines - --symbols Print demangled symbol names found at given addresses - --dot Generate DOT file to stdout - --ps Generate Postcript to stdout - --pdf Generate PDF to stdout - --svg Generate SVG to stdout - --gif Generate GIF to stdout - --raw Generate symbolized jeprof data (useful with remote fetch) - -Heap-Profile Options: - --inuse_space Display in-use (mega)bytes [default] - --inuse_objects Display in-use objects - --alloc_space Display allocated (mega)bytes - --alloc_objects Display allocated objects - --show_bytes Display space in bytes - --drop_negative Ignore negative differences - -Contention-profile options: - --total_delay Display total delay at each region [default] - --contentions Display number of delays at each region - --mean_delay Display mean delay at each region - -Call-graph Options: - --nodecount=<n> Show at most so many nodes [default=80] - --nodefraction=<f> Hide nodes below <f>*total [default=.005] - --edgefraction=<f> Hide edges below <f>*total [default=.001] - --maxdegree=<n> Max incoming/outgoing edges per node [default=8] - --focus=<regexp> Focus on backtraces with nodes matching <regexp> - --thread=<n> Show profile for thread <n> - --ignore=<regexp> Ignore backtraces with nodes matching <regexp> - --scale=<n> Set GV scaling [default=0] - --heapcheck Make nodes with non-0 object counts - (i.e. direct leak generators) more visible - --retain=<regexp> Retain only nodes that match <regexp> - --exclude=<regexp> Exclude all nodes that match <regexp> - -Miscellaneous: - --tools=<prefix or binary:fullpath>[,...] \$PATH for object tool pathnames - --test Run unit tests - --help This message - --version Version information - -Environment Variables: - JEPROF_TMPDIR Profiles directory. Defaults to \$HOME/jeprof - JEPROF_TOOLS Prefix for object tools pathnames - -Examples: - -jeprof /bin/ls ls.prof - Enters "interactive" mode -jeprof --text /bin/ls ls.prof - Outputs one line per procedure -jeprof --web /bin/ls ls.prof - Displays annotated call-graph in web browser -jeprof --gv /bin/ls ls.prof - Displays annotated call-graph via 'gv' -jeprof --gv --focus=Mutex /bin/ls ls.prof - Restricts to code paths including a .*Mutex.* entry -jeprof --gv --focus=Mutex --ignore=string /bin/ls ls.prof - Code paths including Mutex but not string -jeprof --list=getdir /bin/ls ls.prof - (Per-line) annotated source listing for getdir() -jeprof --disasm=getdir /bin/ls ls.prof - (Per-PC) annotated disassembly for getdir() - -jeprof http://localhost:1234/ - Enters "interactive" mode -jeprof --text localhost:1234 - Outputs one line per procedure for localhost:1234 -jeprof --raw localhost:1234 > ./local.raw -jeprof --text ./local.raw - Fetches a remote profile for later analysis and then - analyzes it in text mode. -EOF -} - -sub version_string { - return <<EOF -jeprof (part of jemalloc $JEPROF_VERSION) -based on pprof (part of gperftools $PPROF_VERSION) - -Copyright 1998-2007 Google Inc. - -This is BSD licensed software; see the source for copying conditions -and license information. -There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A -PARTICULAR PURPOSE. -EOF -} - -sub usage { - my $msg = shift; - print STDERR "$msg\n\n"; - print STDERR usage_string(); - print STDERR "\nFATAL ERROR: $msg\n"; # just as a reminder - exit(1); -} - -sub Init() { - # Setup tmp-file name and handler to clean it up. - # We do this in the very beginning so that we can use - # error() and cleanup() function anytime here after. - $main::tmpfile_sym = "/tmp/jeprof$$.sym"; - $main::tmpfile_ps = "/tmp/jeprof$$"; - $main::next_tmpfile = 0; - $SIG{'INT'} = \&sighandler; - - # Cache from filename/linenumber to source code - $main::source_cache = (); - - $main::opt_help = 0; - $main::opt_version = 0; - - $main::opt_cum = 0; - $main::opt_base = ''; - $main::opt_addresses = 0; - $main::opt_lines = 0; - $main::opt_functions = 0; - $main::opt_files = 0; - $main::opt_lib_prefix = ""; - - $main::opt_text = 0; - $main::opt_callgrind = 0; - $main::opt_list = ""; - $main::opt_disasm = ""; - $main::opt_symbols = 0; - $main::opt_gv = 0; - $main::opt_evince = 0; - $main::opt_web = 0; - $main::opt_dot = 0; - $main::opt_ps = 0; - $main::opt_pdf = 0; - $main::opt_gif = 0; - $main::opt_svg = 0; - $main::opt_raw = 0; - - $main::opt_nodecount = 80; - $main::opt_nodefraction = 0.005; - $main::opt_edgefraction = 0.001; - $main::opt_maxdegree = 8; - $main::opt_focus = ''; - $main::opt_thread = undef; - $main::opt_ignore = ''; - $main::opt_scale = 0; - $main::opt_heapcheck = 0; - $main::opt_retain = ''; - $main::opt_exclude = ''; - $main::opt_seconds = 30; - $main::opt_lib = ""; - - $main::opt_inuse_space = 0; - $main::opt_inuse_objects = 0; - $main::opt_alloc_space = 0; - $main::opt_alloc_objects = 0; - $main::opt_show_bytes = 0; - $main::opt_drop_negative = 0; - $main::opt_interactive = 0; - - $main::opt_total_delay = 0; - $main::opt_contentions = 0; - $main::opt_mean_delay = 0; - - $main::opt_tools = ""; - $main::opt_debug = 0; - $main::opt_test = 0; - - # These are undocumented flags used only by unittests. - $main::opt_test_stride = 0; - - # Are we using $SYMBOL_PAGE? - $main::use_symbol_page = 0; - - # Files returned by TempName. - %main::tempnames = (); - - # Type of profile we are dealing with - # Supported types: - # cpu - # heap - # growth - # contention - $main::profile_type = ''; # Empty type means "unknown" - - GetOptions("help!" => \$main::opt_help, - "version!" => \$main::opt_version, - "cum!" => \$main::opt_cum, - "base=s" => \$main::opt_base, - "seconds=i" => \$main::opt_seconds, - "add_lib=s" => \$main::opt_lib, - "lib_prefix=s" => \$main::opt_lib_prefix, - "functions!" => \$main::opt_functions, - "lines!" => \$main::opt_lines, - "addresses!" => \$main::opt_addresses, - "files!" => \$main::opt_files, - "text!" => \$main::opt_text, - "callgrind!" => \$main::opt_callgrind, - "list=s" => \$main::opt_list, - "disasm=s" => \$main::opt_disasm, - "symbols!" => \$main::opt_symbols, - "gv!" => \$main::opt_gv, - "evince!" => \$main::opt_evince, - "web!" => \$main::opt_web, - "dot!" => \$main::opt_dot, - "ps!" => \$main::opt_ps, - "pdf!" => \$main::opt_pdf, - "svg!" => \$main::opt_svg, - "gif!" => \$main::opt_gif, - "raw!" => \$main::opt_raw, - "interactive!" => \$main::opt_interactive, - "nodecount=i" => \$main::opt_nodecount, - "nodefraction=f" => \$main::opt_nodefraction, - "edgefraction=f" => \$main::opt_edgefraction, - "maxdegree=i" => \$main::opt_maxdegree, - "focus=s" => \$main::opt_focus, - "thread=s" => \$main::opt_thread, - "ignore=s" => \$main::opt_ignore, - "scale=i" => \$main::opt_scale, - "heapcheck" => \$main::opt_heapcheck, - "retain=s" => \$main::opt_retain, - "exclude=s" => \$main::opt_exclude, - "inuse_space!" => \$main::opt_inuse_space, - "inuse_objects!" => \$main::opt_inuse_objects, - "alloc_space!" => \$main::opt_alloc_space, - "alloc_objects!" => \$main::opt_alloc_objects, - "show_bytes!" => \$main::opt_show_bytes, - "drop_negative!" => \$main::opt_drop_negative, - "total_delay!" => \$main::opt_total_delay, - "contentions!" => \$main::opt_contentions, - "mean_delay!" => \$main::opt_mean_delay, - "tools=s" => \$main::opt_tools, - "test!" => \$main::opt_test, - "debug!" => \$main::opt_debug, - # Undocumented flags used only by unittests: - "test_stride=i" => \$main::opt_test_stride, - ) || usage("Invalid option(s)"); - - # Deal with the standard --help and --version - if ($main::opt_help) { - print usage_string(); - exit(0); - } - - if ($main::opt_version) { - print version_string(); - exit(0); - } - - # Disassembly/listing/symbols mode requires address-level info - if ($main::opt_disasm || $main::opt_list || $main::opt_symbols) { - $main::opt_functions = 0; - $main::opt_lines = 0; - $main::opt_addresses = 1; - $main::opt_files = 0; - } - - # Check heap-profiling flags - if ($main::opt_inuse_space + - $main::opt_inuse_objects + - $main::opt_alloc_space + - $main::opt_alloc_objects > 1) { - usage("Specify at most on of --inuse/--alloc options"); - } - - # Check output granularities - my $grains = - $main::opt_functions + - $main::opt_lines + - $main::opt_addresses + - $main::opt_files + - 0; - if ($grains > 1) { - usage("Only specify one output granularity option"); - } - if ($grains == 0) { - $main::opt_functions = 1; - } - - # Check output modes - my $modes = - $main::opt_text + - $main::opt_callgrind + - ($main::opt_list eq '' ? 0 : 1) + - ($main::opt_disasm eq '' ? 0 : 1) + - ($main::opt_symbols == 0 ? 0 : 1) + - $main::opt_gv + - $main::opt_evince + - $main::opt_web + - $main::opt_dot + - $main::opt_ps + - $main::opt_pdf + - $main::opt_svg + - $main::opt_gif + - $main::opt_raw + - $main::opt_interactive + - 0; - if ($modes > 1) { - usage("Only specify one output mode"); - } - if ($modes == 0) { - if (-t STDOUT) { # If STDOUT is a tty, activate interactive mode - $main::opt_interactive = 1; - } else { - $main::opt_text = 1; - } - } - - if ($main::opt_test) { - RunUnitTests(); - # Should not return - exit(1); - } - - # Binary name and profile arguments list - $main::prog = ""; - @main::pfile_args = (); - - # Remote profiling without a binary (using $SYMBOL_PAGE instead) - if (@ARGV > 0) { - if (IsProfileURL($ARGV[0])) { - $main::use_symbol_page = 1; - } elsif (IsSymbolizedProfileFile($ARGV[0])) { - $main::use_symbolized_profile = 1; - $main::prog = $UNKNOWN_BINARY; # will be set later from the profile file - } - } - - if ($main::use_symbol_page || $main::use_symbolized_profile) { - # We don't need a binary! - my %disabled = ('--lines' => $main::opt_lines, - '--disasm' => $main::opt_disasm); - for my $option (keys %disabled) { - usage("$option cannot be used without a binary") if $disabled{$option}; - } - # Set $main::prog later... - scalar(@ARGV) || usage("Did not specify profile file"); - } elsif ($main::opt_symbols) { - # --symbols needs a binary-name (to run nm on, etc) but not profiles - $main::prog = shift(@ARGV) || usage("Did not specify program"); - } else { - $main::prog = shift(@ARGV) || usage("Did not specify program"); - scalar(@ARGV) || usage("Did not specify profile file"); - } - - # Parse profile file/location arguments - foreach my $farg (@ARGV) { - if ($farg =~ m/(.*)\@([0-9]+)(|\/.*)$/ ) { - my $machine = $1; - my $num_machines = $2; - my $path = $3; - for (my $i = 0; $i < $num_machines; $i++) { - unshift(@main::pfile_args, "$i.$machine$path"); - } - } else { - unshift(@main::pfile_args, $farg); - } - } - - if ($main::use_symbol_page) { - unless (IsProfileURL($main::pfile_args[0])) { - error("The first profile should be a remote form to use $SYMBOL_PAGE\n"); - } - CheckSymbolPage(); - $main::prog = FetchProgramName(); - } elsif (!$main::use_symbolized_profile) { # may not need objtools! - ConfigureObjTools($main::prog) - } - - # Break the opt_lib_prefix into the prefix_list array - @prefix_list = split (',', $main::opt_lib_prefix); - - # Remove trailing / from the prefixes, in the list to prevent - # searching things like /my/path//lib/mylib.so - foreach (@prefix_list) { - s|/+$||; - } -} - -sub FilterAndPrint { - my ($profile, $symbols, $libs, $thread) = @_; - - # Get total data in profile - my $total = TotalProfile($profile); - - # Remove uniniteresting stack items - $profile = RemoveUninterestingFrames($symbols, $profile); - - # Focus? - if ($main::opt_focus ne '') { - $profile = FocusProfile($symbols, $profile, $main::opt_focus); - } - - # Ignore? - if ($main::opt_ignore ne '') { - $profile = IgnoreProfile($symbols, $profile, $main::opt_ignore); - } - - my $calls = ExtractCalls($symbols, $profile); - - # Reduce profiles to required output granularity, and also clean - # each stack trace so a given entry exists at most once. - my $reduced = ReduceProfile($symbols, $profile); - - # Get derived profiles - my $flat = FlatProfile($reduced); - my $cumulative = CumulativeProfile($reduced); - - # Print - if (!$main::opt_interactive) { - if ($main::opt_disasm) { - PrintDisassembly($libs, $flat, $cumulative, $main::opt_disasm); - } elsif ($main::opt_list) { - PrintListing($total, $libs, $flat, $cumulative, $main::opt_list, 0); - } elsif ($main::opt_text) { - # Make sure the output is empty when have nothing to report - # (only matters when --heapcheck is given but we must be - # compatible with old branches that did not pass --heapcheck always): - if ($total != 0) { - printf("Total%s: %s %s\n", - (defined($thread) ? " (t$thread)" : ""), - Unparse($total), Units()); - } - PrintText($symbols, $flat, $cumulative, -1); - } elsif ($main::opt_raw) { - PrintSymbolizedProfile($symbols, $profile, $main::prog); - } elsif ($main::opt_callgrind) { - PrintCallgrind($calls); - } else { - if (PrintDot($main::prog, $symbols, $profile, $flat, $cumulative, $total)) { - if ($main::opt_gv) { - RunGV(TempName($main::next_tmpfile, "ps"), ""); - } elsif ($main::opt_evince) { - RunEvince(TempName($main::next_tmpfile, "pdf"), ""); - } elsif ($main::opt_web) { - my $tmp = TempName($main::next_tmpfile, "svg"); - RunWeb($tmp); - # The command we run might hand the file name off - # to an already running browser instance and then exit. - # Normally, we'd remove $tmp on exit (right now), - # but fork a child to remove $tmp a little later, so that the - # browser has time to load it first. - delete $main::tempnames{$tmp}; - if (fork() == 0) { - sleep 5; - unlink($tmp); - exit(0); - } - } - } else { - cleanup(); - exit(1); - } - } - } else { - InteractiveMode($profile, $symbols, $libs, $total); - } -} - -sub Main() { - Init(); - $main::collected_profile = undef; - @main::profile_files = (); - $main::op_time = time(); - - # Printing symbols is special and requires a lot less info that most. - if ($main::opt_symbols) { - PrintSymbols(*STDIN); # Get /proc/maps and symbols output from stdin - return; - } - - # Fetch all profile data - FetchDynamicProfiles(); - - # this will hold symbols that we read from the profile files - my $symbol_map = {}; - - # Read one profile, pick the last item on the list - my $data = ReadProfile($main::prog, pop(@main::profile_files)); - my $profile = $data->{profile}; - my $pcs = $data->{pcs}; - my $libs = $data->{libs}; # Info about main program and shared libraries - $symbol_map = MergeSymbols($symbol_map, $data->{symbols}); - - # Add additional profiles, if available. - if (scalar(@main::profile_files) > 0) { - foreach my $pname (@main::profile_files) { - my $data2 = ReadProfile($main::prog, $pname); - $profile = AddProfile($profile, $data2->{profile}); - $pcs = AddPcs($pcs, $data2->{pcs}); - $symbol_map = MergeSymbols($symbol_map, $data2->{symbols}); - } - } - - # Subtract base from profile, if specified - if ($main::opt_base ne '') { - my $base = ReadProfile($main::prog, $main::opt_base); - $profile = SubtractProfile($profile, $base->{profile}); - $pcs = AddPcs($pcs, $base->{pcs}); - $symbol_map = MergeSymbols($symbol_map, $base->{symbols}); - } - - # Collect symbols - my $symbols; - if ($main::use_symbolized_profile) { - $symbols = FetchSymbols($pcs, $symbol_map); - } elsif ($main::use_symbol_page) { - $symbols = FetchSymbols($pcs); - } else { - # TODO(csilvers): $libs uses the /proc/self/maps data from profile1, - # which may differ from the data from subsequent profiles, especially - # if they were run on different machines. Use appropriate libs for - # each pc somehow. - $symbols = ExtractSymbols($libs, $pcs); - } - - if (!defined($main::opt_thread)) { - FilterAndPrint($profile, $symbols, $libs); - } - if (defined($data->{threads})) { - foreach my $thread (sort { $a <=> $b } keys(%{$data->{threads}})) { - if (defined($main::opt_thread) && - ($main::opt_thread eq '*' || $main::opt_thread == $thread)) { - my $thread_profile = $data->{threads}{$thread}; - FilterAndPrint($thread_profile, $symbols, $libs, $thread); - } - } - } - - cleanup(); - exit(0); -} - -##### Entry Point ##### - -Main(); - -# Temporary code to detect if we're running on a Goobuntu system. -# These systems don't have the right stuff installed for the special -# Readline libraries to work, so as a temporary workaround, we default -# to using the normal stdio code, rather than the fancier readline-based -# code -sub ReadlineMightFail { - if (-e '/lib/libtermcap.so.2') { - return 0; # libtermcap exists, so readline should be okay - } else { - return 1; - } -} - -sub RunGV { - my $fname = shift; - my $bg = shift; # "" or " &" if we should run in background - if (!system(ShellEscape(@GV, "--version") . " >$dev_null 2>&1")) { - # Options using double dash are supported by this gv version. - # Also, turn on noantialias to better handle bug in gv for - # postscript files with large dimensions. - # TODO: Maybe we should not pass the --noantialias flag - # if the gv version is known to work properly without the flag. - system(ShellEscape(@GV, "--scale=$main::opt_scale", "--noantialias", $fname) - . $bg); - } else { - # Old gv version - only supports options that use single dash. - print STDERR ShellEscape(@GV, "-scale", $main::opt_scale) . "\n"; - system(ShellEscape(@GV, "-scale", "$main::opt_scale", $fname) . $bg); - } -} - -sub RunEvince { - my $fname = shift; - my $bg = shift; # "" or " &" if we should run in background - system(ShellEscape(@EVINCE, $fname) . $bg); -} - -sub RunWeb { - my $fname = shift; - print STDERR "Loading web page file:///$fname\n"; - - if (`uname` =~ /Darwin/) { - # OS X: open will use standard preference for SVG files. - system("/usr/bin/open", $fname); - return; - } - - # Some kind of Unix; try generic symlinks, then specific browsers. - # (Stop once we find one.) - # Works best if the browser is already running. - my @alt = ( - "/etc/alternatives/gnome-www-browser", - "/etc/alternatives/x-www-browser", - "google-chrome", - "firefox", - ); - foreach my $b (@alt) { - if (system($b, $fname) == 0) { - return; - } - } - - print STDERR "Could not load web browser.\n"; -} - -sub RunKcachegrind { - my $fname = shift; - my $bg = shift; # "" or " &" if we should run in background - print STDERR "Starting '@KCACHEGRIND " . $fname . $bg . "'\n"; - system(ShellEscape(@KCACHEGRIND, $fname) . $bg); -} - - -##### Interactive helper routines ##### - -sub InteractiveMode { - $| = 1; # Make output unbuffered for interactive mode - my ($orig_profile, $symbols, $libs, $total) = @_; - - print STDERR "Welcome to jeprof! For help, type 'help'.\n"; - - # Use ReadLine if it's installed and input comes from a console. - if ( -t STDIN && - !ReadlineMightFail() && - defined(eval {require Term::ReadLine}) ) { - my $term = new Term::ReadLine 'jeprof'; - while ( defined ($_ = $term->readline('(jeprof) '))) { - $term->addhistory($_) if /\S/; - if (!InteractiveCommand($orig_profile, $symbols, $libs, $total, $_)) { - last; # exit when we get an interactive command to quit - } - } - } else { # don't have readline - while (1) { - print STDERR "(jeprof) "; - $_ = <STDIN>; - last if ! defined $_ ; - s/\r//g; # turn windows-looking lines into unix-looking lines - - # Save some flags that might be reset by InteractiveCommand() - my $save_opt_lines = $main::opt_lines; - - if (!InteractiveCommand($orig_profile, $symbols, $libs, $total, $_)) { - last; # exit when we get an interactive command to quit - } - - # Restore flags - $main::opt_lines = $save_opt_lines; - } - } -} - -# Takes two args: orig profile, and command to run. -# Returns 1 if we should keep going, or 0 if we were asked to quit -sub InteractiveCommand { - my($orig_profile, $symbols, $libs, $total, $command) = @_; - $_ = $command; # just to make future m//'s easier - if (!defined($_)) { - print STDERR "\n"; - return 0; - } - if (m/^\s*quit/) { - return 0; - } - if (m/^\s*help/) { - InteractiveHelpMessage(); - return 1; - } - # Clear all the mode options -- mode is controlled by "$command" - $main::opt_text = 0; - $main::opt_callgrind = 0; - $main::opt_disasm = 0; - $main::opt_list = 0; - $main::opt_gv = 0; - $main::opt_evince = 0; - $main::opt_cum = 0; - - if (m/^\s*(text|top)(\d*)\s*(.*)/) { - $main::opt_text = 1; - - my $line_limit = ($2 ne "") ? int($2) : 10; - - my $routine; - my $ignore; - ($routine, $ignore) = ParseInteractiveArgs($3); - - my $profile = ProcessProfile($total, $orig_profile, $symbols, "", $ignore); - my $reduced = ReduceProfile($symbols, $profile); - - # Get derived profiles - my $flat = FlatProfile($reduced); - my $cumulative = CumulativeProfile($reduced); - - PrintText($symbols, $flat, $cumulative, $line_limit); - return 1; - } - if (m/^\s*callgrind\s*([^ \n]*)/) { - $main::opt_callgrind = 1; - - # Get derived profiles - my $calls = ExtractCalls($symbols, $orig_profile); - my $filename = $1; - if ( $1 eq '' ) { - $filename = TempName($main::next_tmpfile, "callgrind"); - } - PrintCallgrind($calls, $filename); - if ( $1 eq '' ) { - RunKcachegrind($filename, " & "); - $main::next_tmpfile++; - } - - return 1; - } - if (m/^\s*(web)?list\s*(.+)/) { - my $html = (defined($1) && ($1 eq "web")); - $main::opt_list = 1; - - my $routine; - my $ignore; - ($routine, $ignore) = ParseInteractiveArgs($2); - - my $profile = ProcessProfile($total, $orig_profile, $symbols, "", $ignore); - my $reduced = ReduceProfile($symbols, $profile); - - # Get derived profiles - my $flat = FlatProfile($reduced); - my $cumulative = CumulativeProfile($reduced); - - PrintListing($total, $libs, $flat, $cumulative, $routine, $html); - return 1; - } - if (m/^\s*disasm\s*(.+)/) { - $main::opt_disasm = 1; - - my $routine; - my $ignore; - ($routine, $ignore) = ParseInteractiveArgs($1); - - # Process current profile to account for various settings - my $profile = ProcessProfile($total, $orig_profile, $symbols, "", $ignore); - my $reduced = ReduceProfile($symbols, $profile); - - # Get derived profiles - my $flat = FlatProfile($reduced); - my $cumulative = CumulativeProfile($reduced); - - PrintDisassembly($libs, $flat, $cumulative, $routine); - return 1; - } - if (m/^\s*(gv|web|evince)\s*(.*)/) { - $main::opt_gv = 0; - $main::opt_evince = 0; - $main::opt_web = 0; - if ($1 eq "gv") { - $main::opt_gv = 1; - } elsif ($1 eq "evince") { - $main::opt_evince = 1; - } elsif ($1 eq "web") { - $main::opt_web = 1; - } - - my $focus; - my $ignore; - ($focus, $ignore) = ParseInteractiveArgs($2); - - # Process current profile to account for various settings - my $profile = ProcessProfile($total, $orig_profile, $symbols, - $focus, $ignore); - my $reduced = ReduceProfile($symbols, $profile); - - # Get derived profiles - my $flat = FlatProfile($reduced); - my $cumulative = CumulativeProfile($reduced); - - if (PrintDot($main::prog, $symbols, $profile, $flat, $cumulative, $total)) { - if ($main::opt_gv) { - RunGV(TempName($main::next_tmpfile, "ps"), " &"); - } elsif ($main::opt_evince) { - RunEvince(TempName($main::next_tmpfile, "pdf"), " &"); - } elsif ($main::opt_web) { - RunWeb(TempName($main::next_tmpfile, "svg")); - } - $main::next_tmpfile++; - } - return 1; - } - if (m/^\s*$/) { - return 1; - } - print STDERR "Unknown command: try 'help'.\n"; - return 1; -} - - -sub ProcessProfile { - my $total_count = shift; - my $orig_profile = shift; - my $symbols = shift; - my $focus = shift; - my $ignore = shift; - - # Process current profile to account for various settings - my $profile = $orig_profile; - printf("Total: %s %s\n", Unparse($total_count), Units()); - if ($focus ne '') { - $profile = FocusProfile($symbols, $profile, $focus); - my $focus_count = TotalProfile($profile); - printf("After focusing on '%s': %s %s of %s (%0.1f%%)\n", - $focus, - Unparse($focus_count), Units(), - Unparse($total_count), ($focus_count*100.0) / $total_count); - } - if ($ignore ne '') { - $profile = IgnoreProfile($symbols, $profile, $ignore); - my $ignore_count = TotalProfile($profile); - printf("After ignoring '%s': %s %s of %s (%0.1f%%)\n", - $ignore, - Unparse($ignore_count), Units(), - Unparse($total_count), - ($ignore_count*100.0) / $total_count); - } - - return $profile; -} - -sub InteractiveHelpMessage { - print STDERR <<ENDOFHELP; -Interactive jeprof mode - -Commands: - gv - gv [focus] [-ignore1] [-ignore2] - Show graphical hierarchical display of current profile. Without - any arguments, shows all samples in the profile. With the optional - "focus" argument, restricts the samples shown to just those where - the "focus" regular expression matches a routine name on the stack - trace. - - web - web [focus] [-ignore1] [-ignore2] - Like GV, but displays profile in your web browser instead of using - Ghostview. Works best if your web browser is already running. - To change the browser that gets used: - On Linux, set the /etc/alternatives/gnome-www-browser symlink. - On OS X, change the Finder association for SVG files. - - list [routine_regexp] [-ignore1] [-ignore2] - Show source listing of routines whose names match "routine_regexp" - - weblist [routine_regexp] [-ignore1] [-ignore2] - Displays a source listing of routines whose names match "routine_regexp" - in a web browser. You can click on source lines to view the - corresponding disassembly. - - top [--cum] [-ignore1] [-ignore2] - top20 [--cum] [-ignore1] [-ignore2] - top37 [--cum] [-ignore1] [-ignore2] - Show top lines ordered by flat profile count, or cumulative count - if --cum is specified. If a number is present after 'top', the - top K routines will be shown (defaults to showing the top 10) - - disasm [routine_regexp] [-ignore1] [-ignore2] - Show disassembly of routines whose names match "routine_regexp", - annotated with sample counts. - - callgrind - callgrind [filename] - Generates callgrind file. If no filename is given, kcachegrind is called. - - help - This listing - quit or ^D - End jeprof - -For commands that accept optional -ignore tags, samples where any routine in -the stack trace matches the regular expression in any of the -ignore -parameters will be ignored. - -Further pprof details are available at this location (or one similar): - - /usr/doc/gperftools-$PPROF_VERSION/cpu_profiler.html - /usr/doc/gperftools-$PPROF_VERSION/heap_profiler.html - -ENDOFHELP -} -sub ParseInteractiveArgs { - my $args = shift; - my $focus = ""; - my $ignore = ""; - my @x = split(/ +/, $args); - foreach $a (@x) { - if ($a =~ m/^(--|-)lines$/) { - $main::opt_lines = 1; - } elsif ($a =~ m/^(--|-)cum$/) { - $main::opt_cum = 1; - } elsif ($a =~ m/^-(.*)/) { - $ignore .= (($ignore ne "") ? "|" : "" ) . $1; - } else { - $focus .= (($focus ne "") ? "|" : "" ) . $a; - } - } - if ($ignore ne "") { - print STDERR "Ignoring samples in call stacks that match '$ignore'\n"; - } - return ($focus, $ignore); -} - -##### Output code ##### - -sub TempName { - my $fnum = shift; - my $ext = shift; - my $file = "$main::tmpfile_ps.$fnum.$ext"; - $main::tempnames{$file} = 1; - return $file; -} - -# Print profile data in packed binary format (64-bit) to standard out -sub PrintProfileData { - my $profile = shift; - - # print header (64-bit style) - # (zero) (header-size) (version) (sample-period) (zero) - print pack('L*', 0, 0, 3, 0, 0, 0, 1, 0, 0, 0); - - foreach my $k (keys(%{$profile})) { - my $count = $profile->{$k}; - my @addrs = split(/\n/, $k); - if ($#addrs >= 0) { - my $depth = $#addrs + 1; - # int(foo / 2**32) is the only reliable way to get rid of bottom - # 32 bits on both 32- and 64-bit systems. - print pack('L*', $count & 0xFFFFFFFF, int($count / 2**32)); - print pack('L*', $depth & 0xFFFFFFFF, int($depth / 2**32)); - - foreach my $full_addr (@addrs) { - my $addr = $full_addr; - $addr =~ s/0x0*//; # strip off leading 0x, zeroes - if (length($addr) > 16) { - print STDERR "Invalid address in profile: $full_addr\n"; - next; - } - my $low_addr = substr($addr, -8); # get last 8 hex chars - my $high_addr = substr($addr, -16, 8); # get up to 8 more hex chars - print pack('L*', hex('0x' . $low_addr), hex('0x' . $high_addr)); - } - } - } -} - -# Print symbols and profile data -sub PrintSymbolizedProfile { - my $symbols = shift; - my $profile = shift; - my $prog = shift; - - $SYMBOL_PAGE =~ m,[^/]+$,; # matches everything after the last slash - my $symbol_marker = $&; - - print '--- ', $symbol_marker, "\n"; - if (defined($prog)) { - print 'binary=', $prog, "\n"; - } - while (my ($pc, $name) = each(%{$symbols})) { - my $sep = ' '; - print '0x', $pc; - # We have a list of function names, which include the inlined - # calls. They are separated (and terminated) by --, which is - # illegal in function names. - for (my $j = 2; $j <= $#{$name}; $j += 3) { - print $sep, $name->[$j]; - $sep = '--'; - } - print "\n"; - } - print '---', "\n"; - - my $profile_marker; - if ($main::profile_type eq 'heap') { - $HEAP_PAGE =~ m,[^/]+$,; # matches everything after the last slash - $profile_marker = $&; - } elsif ($main::profile_type eq 'growth') { - $GROWTH_PAGE =~ m,[^/]+$,; # matches everything after the last slash - $profile_marker = $&; - } elsif ($main::profile_type eq 'contention') { - $CONTENTION_PAGE =~ m,[^/]+$,; # matches everything after the last slash - $profile_marker = $&; - } else { # elsif ($main::profile_type eq 'cpu') - $PROFILE_PAGE =~ m,[^/]+$,; # matches everything after the last slash - $profile_marker = $&; - } - - print '--- ', $profile_marker, "\n"; - if (defined($main::collected_profile)) { - # if used with remote fetch, simply dump the collected profile to output. - open(SRC, "<$main::collected_profile"); - while (<SRC>) { - print $_; - } - close(SRC); - } else { - # --raw/http: For everything to work correctly for non-remote profiles, we - # would need to extend PrintProfileData() to handle all possible profile - # types, re-enable the code that is currently disabled in ReadCPUProfile() - # and FixCallerAddresses(), and remove the remote profile dumping code in - # the block above. - die "--raw/http: jeprof can only dump remote profiles for --raw\n"; - # dump a cpu-format profile to standard out - PrintProfileData($profile); - } -} - -# Print text output -sub PrintText { - my $symbols = shift; - my $flat = shift; - my $cumulative = shift; - my $line_limit = shift; - - my $total = TotalProfile($flat); - - # Which profile to sort by? - my $s = $main::opt_cum ? $cumulative : $flat; - - my $running_sum = 0; - my $lines = 0; - foreach my $k (sort { GetEntry($s, $b) <=> GetEntry($s, $a) || $a cmp $b } - keys(%{$cumulative})) { - my $f = GetEntry($flat, $k); - my $c = GetEntry($cumulative, $k); - $running_sum += $f; - - my $sym = $k; - if (exists($symbols->{$k})) { - $sym = $symbols->{$k}->[0] . " " . $symbols->{$k}->[1]; - if ($main::opt_addresses) { - $sym = $k . " " . $sym; - } - } - - if ($f != 0 || $c != 0) { - printf("%8s %6s %6s %8s %6s %s\n", - Unparse($f), - Percent($f, $total), - Percent($running_sum, $total), - Unparse($c), - Percent($c, $total), - $sym); - } - $lines++; - last if ($line_limit >= 0 && $lines >= $line_limit); - } -} - -# Callgrind format has a compression for repeated function and file -# names. You show the name the first time, and just use its number -# subsequently. This can cut down the file to about a third or a -# quarter of its uncompressed size. $key and $val are the key/value -# pair that would normally be printed by callgrind; $map is a map from -# value to number. -sub CompressedCGName { - my($key, $val, $map) = @_; - my $idx = $map->{$val}; - # For very short keys, providing an index hurts rather than helps. - if (length($val) <= 3) { - return "$key=$val\n"; - } elsif (defined($idx)) { - return "$key=($idx)\n"; - } else { - # scalar(keys $map) gives the number of items in the map. - $idx = scalar(keys(%{$map})) + 1; - $map->{$val} = $idx; - return "$key=($idx) $val\n"; - } -} - -# Print the call graph in a way that's suiteable for callgrind. -sub PrintCallgrind { - my $calls = shift; - my $filename; - my %filename_to_index_map; - my %fnname_to_index_map; - - if ($main::opt_interactive) { - $filename = shift; - print STDERR "Writing callgrind file to '$filename'.\n" - } else { - $filename = "&STDOUT"; - } - open(CG, ">$filename"); - printf CG ("events: Hits\n\n"); - foreach my $call ( map { $_->[0] } - sort { $a->[1] cmp $b ->[1] || - $a->[2] <=> $b->[2] } - map { /([^:]+):(\d+):([^ ]+)( -> ([^:]+):(\d+):(.+))?/; - [$_, $1, $2] } - keys %$calls ) { - my $count = int($calls->{$call}); - $call =~ /([^:]+):(\d+):([^ ]+)( -> ([^:]+):(\d+):(.+))?/; - my ( $caller_file, $caller_line, $caller_function, - $callee_file, $callee_line, $callee_function ) = - ( $1, $2, $3, $5, $6, $7 ); - - # TODO(csilvers): for better compression, collect all the - # caller/callee_files and functions first, before printing - # anything, and only compress those referenced more than once. - printf CG CompressedCGName("fl", $caller_file, \%filename_to_index_map); - printf CG CompressedCGName("fn", $caller_function, \%fnname_to_index_map); - if (defined $6) { - printf CG CompressedCGName("cfl", $callee_file, \%filename_to_index_map); - printf CG CompressedCGName("cfn", $callee_function, \%fnname_to_index_map); - printf CG ("calls=$count $callee_line\n"); - } - printf CG ("$caller_line $count\n\n"); - } -} - -# Print disassembly for all all routines that match $main::opt_disasm -sub PrintDisassembly { - my $libs = shift; - my $flat = shift; - my $cumulative = shift; - my $disasm_opts = shift; - - my $total = TotalProfile($flat); - - foreach my $lib (@{$libs}) { - my $symbol_table = GetProcedureBoundaries($lib->[0], $disasm_opts); - my $offset = AddressSub($lib->[1], $lib->[3]); - foreach my $routine (sort ByName keys(%{$symbol_table})) { - my $start_addr = $symbol_table->{$routine}->[0]; - my $end_addr = $symbol_table->{$routine}->[1]; - # See if there are any samples in this routine - my $length = hex(AddressSub($end_addr, $start_addr)); - my $addr = AddressAdd($start_addr, $offset); - for (my $i = 0; $i < $length; $i++) { - if (defined($cumulative->{$addr})) { - PrintDisassembledFunction($lib->[0], $offset, - $routine, $flat, $cumulative, - $start_addr, $end_addr, $total); - last; - } - $addr = AddressInc($addr); - } - } - } -} - -# Return reference to array of tuples of the form: -# [start_address, filename, linenumber, instruction, limit_address] -# E.g., -# ["0x806c43d", "/foo/bar.cc", 131, "ret", "0x806c440"] -sub Disassemble { - my $prog = shift; - my $offset = shift; - my $start_addr = shift; - my $end_addr = shift; - - my $objdump = $obj_tool_map{"objdump"}; - my $cmd = ShellEscape($objdump, "-C", "-d", "-l", "--no-show-raw-insn", - "--start-address=0x$start_addr", - "--stop-address=0x$end_addr", $prog); - open(OBJDUMP, "$cmd |") || error("$cmd: $!\n"); - my @result = (); - my $filename = ""; - my $linenumber = -1; - my $last = ["", "", "", ""]; - while (<OBJDUMP>) { - s/\r//g; # turn windows-looking lines into unix-looking lines - chop; - if (m|\s*([^:\s]+):(\d+)\s*$|) { - # Location line of the form: - # <filename>:<linenumber> - $filename = $1; - $linenumber = $2; - } elsif (m/^ +([0-9a-f]+):\s*(.*)/) { - # Disassembly line -- zero-extend address to full length - my $addr = HexExtend($1); - my $k = AddressAdd($addr, $offset); - $last->[4] = $k; # Store ending address for previous instruction - $last = [$k, $filename, $linenumber, $2, $end_addr]; - push(@result, $last); - } - } - close(OBJDUMP); - return @result; -} - -# The input file should contain lines of the form /proc/maps-like -# output (same format as expected from the profiles) or that looks -# like hex addresses (like "0xDEADBEEF"). We will parse all -# /proc/maps output, and for all the hex addresses, we will output -# "short" symbol names, one per line, in the same order as the input. -sub PrintSymbols { - my $maps_and_symbols_file = shift; - - # ParseLibraries expects pcs to be in a set. Fine by us... - my @pclist = (); # pcs in sorted order - my $pcs = {}; - my $map = ""; - foreach my $line (<$maps_and_symbols_file>) { - $line =~ s/\r//g; # turn windows-looking lines into unix-looking lines - if ($line =~ /\b(0x[0-9a-f]+)\b/i) { - push(@pclist, HexExtend($1)); - $pcs->{$pclist[-1]} = 1; - } else { - $map .= $line; - } - } - - my $libs = ParseLibraries($main::prog, $map, $pcs); - my $symbols = ExtractSymbols($libs, $pcs); - - foreach my $pc (@pclist) { - # ->[0] is the shortname, ->[2] is the full name - print(($symbols->{$pc}->[0] || "??") . "\n"); - } -} - - -# For sorting functions by name -sub ByName { - return ShortFunctionName($a) cmp ShortFunctionName($b); -} - -# Print source-listing for all all routines that match $list_opts -sub PrintListing { - my $total = shift; - my $libs = shift; - my $flat = shift; - my $cumulative = shift; - my $list_opts = shift; - my $html = shift; - - my $output = \*STDOUT; - my $fname = ""; - - if ($html) { - # Arrange to write the output to a temporary file - $fname = TempName($main::next_tmpfile, "html"); - $main::next_tmpfile++; - if (!open(TEMP, ">$fname")) { - print STDERR "$fname: $!\n"; - return; - } - $output = \*TEMP; - print $output HtmlListingHeader(); - printf $output ("<div class=\"legend\">%s<br>Total: %s %s</div>\n", - $main::prog, Unparse($total), Units()); - } - - my $listed = 0; - foreach my $lib (@{$libs}) { - my $symbol_table = GetProcedureBoundaries($lib->[0], $list_opts); - my $offset = AddressSub($lib->[1], $lib->[3]); - foreach my $routine (sort ByName keys(%{$symbol_table})) { - # Print if there are any samples in this routine - my $start_addr = $symbol_table->{$routine}->[0]; - my $end_addr = $symbol_table->{$routine}->[1]; - my $length = hex(AddressSub($end_addr, $start_addr)); - my $addr = AddressAdd($start_addr, $offset); - for (my $i = 0; $i < $length; $i++) { - if (defined($cumulative->{$addr})) { - $listed += PrintSource( - $lib->[0], $offset, - $routine, $flat, $cumulative, - $start_addr, $end_addr, - $html, - $output); - last; - } - $addr = AddressInc($addr); - } - } - } - - if ($html) { - if ($listed > 0) { - print $output HtmlListingFooter(); - close($output); - RunWeb($fname); - } else { - close($output); - unlink($fname); - } - } -} - -sub HtmlListingHeader { - return <<'EOF'; -<DOCTYPE html> -<html> -<head> -<title>Pprof listing</title> -<style type="text/css"> -body { - font-family: sans-serif; -} -h1 { - font-size: 1.5em; - margin-bottom: 4px; -} -.legend { - font-size: 1.25em; -} -.line { - color: #aaaaaa; -} -.nop { - color: #aaaaaa; -} -.unimportant { - color: #cccccc; -} -.disasmloc { - color: #000000; -} -.deadsrc { - cursor: pointer; -} -.deadsrc:hover { - background-color: #eeeeee; -} -.livesrc { - color: #0000ff; - cursor: pointer; -} -.livesrc:hover { - background-color: #eeeeee; -} -.asm { - color: #008800; - display: none; -} -</style> -<script type="text/javascript"> -function jeprof_toggle_asm(e) { - var target; - if (!e) e = window.event; - if (e.target) target = e.target; - else if (e.srcElement) target = e.srcElement; - - if (target) { - var asm = target.nextSibling; - if (asm && asm.className == "asm") { - asm.style.display = (asm.style.display == "block" ? "" : "block"); - e.preventDefault(); - return false; - } - } -} -</script> -</head> -<body> -EOF -} - -sub HtmlListingFooter { - return <<'EOF'; -</body> -</html> -EOF -} - -sub HtmlEscape { - my $text = shift; - $text =~ s/&/&/g; - $text =~ s/</</g; - $text =~ s/>/>/g; - return $text; -} - -# Returns the indentation of the line, if it has any non-whitespace -# characters. Otherwise, returns -1. -sub Indentation { - my $line = shift; - if (m/^(\s*)\S/) { - return length($1); - } else { - return -1; - } -} - -# If the symbol table contains inlining info, Disassemble() may tag an -# instruction with a location inside an inlined function. But for -# source listings, we prefer to use the location in the function we -# are listing. So use MapToSymbols() to fetch full location -# information for each instruction and then pick out the first -# location from a location list (location list contains callers before -# callees in case of inlining). -# -# After this routine has run, each entry in $instructions contains: -# [0] start address -# [1] filename for function we are listing -# [2] line number for function we are listing -# [3] disassembly -# [4] limit address -# [5] most specific filename (may be different from [1] due to inlining) -# [6] most specific line number (may be different from [2] due to inlining) -sub GetTopLevelLineNumbers { - my ($lib, $offset, $instructions) = @_; - my $pcs = []; - for (my $i = 0; $i <= $#{$instructions}; $i++) { - push(@{$pcs}, $instructions->[$i]->[0]); - } - my $symbols = {}; - MapToSymbols($lib, $offset, $pcs, $symbols); - for (my $i = 0; $i <= $#{$instructions}; $i++) { - my $e = $instructions->[$i]; - push(@{$e}, $e->[1]); - push(@{$e}, $e->[2]); - my $addr = $e->[0]; - my $sym = $symbols->{$addr}; - if (defined($sym)) { - if ($#{$sym} >= 2 && $sym->[1] =~ m/^(.*):(\d+)$/) { - $e->[1] = $1; # File name - $e->[2] = $2; # Line number - } - } - } -} - -# Print source-listing for one routine -sub PrintSource { - my $prog = shift; - my $offset = shift; - my $routine = shift; - my $flat = shift; - my $cumulative = shift; - my $start_addr = shift; - my $end_addr = shift; - my $html = shift; - my $output = shift; - - # Disassemble all instructions (just to get line numbers) - my @instructions = Disassemble($prog, $offset, $start_addr, $end_addr); - GetTopLevelLineNumbers($prog, $offset, \@instructions); - - # Hack 1: assume that the first source file encountered in the - # disassembly contains the routine - my $filename = undef; - for (my $i = 0; $i <= $#instructions; $i++) { - if ($instructions[$i]->[2] >= 0) { - $filename = $instructions[$i]->[1]; - last; - } - } - if (!defined($filename)) { - print STDERR "no filename found in $routine\n"; - return 0; - } - - # Hack 2: assume that the largest line number from $filename is the - # end of the procedure. This is typically safe since if P1 contains - # an inlined call to P2, then P2 usually occurs earlier in the - # source file. If this does not work, we might have to compute a - # density profile or just print all regions we find. - my $lastline = 0; - for (my $i = 0; $i <= $#instructions; $i++) { - my $f = $instructions[$i]->[1]; - my $l = $instructions[$i]->[2]; - if (($f eq $filename) && ($l > $lastline)) { - $lastline = $l; - } - } - - # Hack 3: assume the first source location from "filename" is the start of - # the source code. - my $firstline = 1; - for (my $i = 0; $i <= $#instructions; $i++) { - if ($instructions[$i]->[1] eq $filename) { - $firstline = $instructions[$i]->[2]; - last; - } - } - - # Hack 4: Extend last line forward until its indentation is less than - # the indentation we saw on $firstline - my $oldlastline = $lastline; - { - if (!open(FILE, "<$filename")) { - print STDERR "$filename: $!\n"; - return 0; - } - my $l = 0; - my $first_indentation = -1; - while (<FILE>) { - s/\r//g; # turn windows-looking lines into unix-looking lines - $l++; - my $indent = Indentation($_); - if ($l >= $firstline) { - if ($first_indentation < 0 && $indent >= 0) { - $first_indentation = $indent; - last if ($first_indentation == 0); - } - } - if ($l >= $lastline && $indent >= 0) { - if ($indent >= $first_indentation) { - $lastline = $l+1; - } else { - last; - } - } - } - close(FILE); - } - - # Assign all samples to the range $firstline,$lastline, - # Hack 4: If an instruction does not occur in the range, its samples - # are moved to the next instruction that occurs in the range. - my $samples1 = {}; # Map from line number to flat count - my $samples2 = {}; # Map from line number to cumulative count - my $running1 = 0; # Unassigned flat counts - my $running2 = 0; # Unassigned cumulative counts - my $total1 = 0; # Total flat counts - my $total2 = 0; # Total cumulative counts - my %disasm = (); # Map from line number to disassembly - my $running_disasm = ""; # Unassigned disassembly - my $skip_marker = "---\n"; - if ($html) { - $skip_marker = ""; - for (my $l = $firstline; $l <= $lastline; $l++) { - $disasm{$l} = ""; - } - } - my $last_dis_filename = ''; - my $last_dis_linenum = -1; - my $last_touched_line = -1; # To detect gaps in disassembly for a line - foreach my $e (@instructions) { - # Add up counts for all address that fall inside this instruction - my $c1 = 0; - my $c2 = 0; - for (my $a = $e->[0]; $a lt $e->[4]; $a = AddressInc($a)) { - $c1 += GetEntry($flat, $a); - $c2 += GetEntry($cumulative, $a); - } - - if ($html) { - my $dis = sprintf(" %6s %6s \t\t%8s: %s ", - HtmlPrintNumber($c1), - HtmlPrintNumber($c2), - UnparseAddress($offset, $e->[0]), - CleanDisassembly($e->[3])); - - # Append the most specific source line associated with this instruction - if (length($dis) < 80) { $dis .= (' ' x (80 - length($dis))) }; - $dis = HtmlEscape($dis); - my $f = $e->[5]; - my $l = $e->[6]; - if ($f ne $last_dis_filename) { - $dis .= sprintf("<span class=disasmloc>%s:%d</span>", - HtmlEscape(CleanFileName($f)), $l); - } elsif ($l ne $last_dis_linenum) { - # De-emphasize the unchanged file name portion - $dis .= sprintf("<span class=unimportant>%s</span>" . - "<span class=disasmloc>:%d</span>", - HtmlEscape(CleanFileName($f)), $l); - } else { - # De-emphasize the entire location - $dis .= sprintf("<span class=unimportant>%s:%d</span>", - HtmlEscape(CleanFileName($f)), $l); - } - $last_dis_filename = $f; - $last_dis_linenum = $l; - $running_disasm .= $dis; - $running_disasm .= "\n"; - } - - $running1 += $c1; - $running2 += $c2; - $total1 += $c1; - $total2 += $c2; - my $file = $e->[1]; - my $line = $e->[2]; - if (($file eq $filename) && - ($line >= $firstline) && - ($line <= $lastline)) { - # Assign all accumulated samples to this line - AddEntry($samples1, $line, $running1); - AddEntry($samples2, $line, $running2); - $running1 = 0; - $running2 = 0; - if ($html) { - if ($line != $last_touched_line && $disasm{$line} ne '') { - $disasm{$line} .= "\n"; - } - $disasm{$line} .= $running_disasm; - $running_disasm = ''; - $last_touched_line = $line; - } - } - } - - # Assign any leftover samples to $lastline - AddEntry($samples1, $lastline, $running1); - AddEntry($samples2, $lastline, $running2); - if ($html) { - if ($lastline != $last_touched_line && $disasm{$lastline} ne '') { - $disasm{$lastline} .= "\n"; - } - $disasm{$lastline} .= $running_disasm; - } - - if ($html) { - printf $output ( - "<h1>%s</h1>%s\n<pre onClick=\"jeprof_toggle_asm()\">\n" . - "Total:%6s %6s (flat / cumulative %s)\n", - HtmlEscape(ShortFunctionName($routine)), - HtmlEscape(CleanFileName($filename)), - Unparse($total1), - Unparse($total2), - Units()); - } else { - printf $output ( - "ROUTINE ====================== %s in %s\n" . - "%6s %6s Total %s (flat / cumulative)\n", - ShortFunctionName($routine), - CleanFileName($filename), - Unparse($total1), - Unparse($total2), - Units()); - } - if (!open(FILE, "<$filename")) { - print STDERR "$filename: $!\n"; - return 0; - } - my $l = 0; - while (<FILE>) { - s/\r//g; # turn windows-looking lines into unix-looking lines - $l++; - if ($l >= $firstline - 5 && - (($l <= $oldlastline + 5) || ($l <= $lastline))) { - chop; - my $text = $_; - if ($l == $firstline) { print $output $skip_marker; } - my $n1 = GetEntry($samples1, $l); - my $n2 = GetEntry($samples2, $l); - if ($html) { - # Emit a span that has one of the following classes: - # livesrc -- has samples - # deadsrc -- has disassembly, but with no samples - # nop -- has no matching disasembly - # Also emit an optional span containing disassembly. - my $dis = $disasm{$l}; - my $asm = ""; - if (defined($dis) && $dis ne '') { - $asm = "<span class=\"asm\">" . $dis . "</span>"; - } - my $source_class = (($n1 + $n2 > 0) - ? "livesrc" - : (($asm ne "") ? "deadsrc" : "nop")); - printf $output ( - "<span class=\"line\">%5d</span> " . - "<span class=\"%s\">%6s %6s %s</span>%s\n", - $l, $source_class, - HtmlPrintNumber($n1), - HtmlPrintNumber($n2), - HtmlEscape($text), - $asm); - } else { - printf $output( - "%6s %6s %4d: %s\n", - UnparseAlt($n1), - UnparseAlt($n2), - $l, - $text); - } - if ($l == $lastline) { print $output $skip_marker; } - }; - } - close(FILE); - if ($html) { - print $output "</pre>\n"; - } - return 1; -} - -# Return the source line for the specified file/linenumber. -# Returns undef if not found. -sub SourceLine { - my $file = shift; - my $line = shift; - - # Look in cache - if (!defined($main::source_cache{$file})) { - if (100 < scalar keys(%main::source_cache)) { - # Clear the cache when it gets too big - $main::source_cache = (); - } - - # Read all lines from the file - if (!open(FILE, "<$file")) { - print STDERR "$file: $!\n"; - $main::source_cache{$file} = []; # Cache the negative result - return undef; - } - my $lines = []; - push(@{$lines}, ""); # So we can use 1-based line numbers as indices - while (<FILE>) { - push(@{$lines}, $_); - } - close(FILE); - - # Save the lines in the cache - $main::source_cache{$file} = $lines; - } - - my $lines = $main::source_cache{$file}; - if (($line < 0) || ($line > $#{$lines})) { - return undef; - } else { - return $lines->[$line]; - } -} - -# Print disassembly for one routine with interspersed source if available -sub PrintDisassembledFunction { - my $prog = shift; - my $offset = shift; - my $routine = shift; - my $flat = shift; - my $cumulative = shift; - my $start_addr = shift; - my $end_addr = shift; - my $total = shift; - - # Disassemble all instructions - my @instructions = Disassemble($prog, $offset, $start_addr, $end_addr); - - # Make array of counts per instruction - my @flat_count = (); - my @cum_count = (); - my $flat_total = 0; - my $cum_total = 0; - foreach my $e (@instructions) { - # Add up counts for all address that fall inside this instruction - my $c1 = 0; - my $c2 = 0; - for (my $a = $e->[0]; $a lt $e->[4]; $a = AddressInc($a)) { - $c1 += GetEntry($flat, $a); - $c2 += GetEntry($cumulative, $a); - } - push(@flat_count, $c1); - push(@cum_count, $c2); - $flat_total += $c1; - $cum_total += $c2; - } - - # Print header with total counts - printf("ROUTINE ====================== %s\n" . - "%6s %6s %s (flat, cumulative) %.1f%% of total\n", - ShortFunctionName($routine), - Unparse($flat_total), - Unparse($cum_total), - Units(), - ($cum_total * 100.0) / $total); - - # Process instructions in order - my $current_file = ""; - for (my $i = 0; $i <= $#instructions; ) { - my $e = $instructions[$i]; - - # Print the new file name whenever we switch files - if ($e->[1] ne $current_file) { - $current_file = $e->[1]; - my $fname = $current_file; - $fname =~ s|^\./||; # Trim leading "./" - - # Shorten long file names - if (length($fname) >= 58) { - $fname = "..." . substr($fname, -55); - } - printf("-------------------- %s\n", $fname); - } - - # TODO: Compute range of lines to print together to deal with - # small reorderings. - my $first_line = $e->[2]; - my $last_line = $first_line; - my %flat_sum = (); - my %cum_sum = (); - for (my $l = $first_line; $l <= $last_line; $l++) { - $flat_sum{$l} = 0; - $cum_sum{$l} = 0; - } - - # Find run of instructions for this range of source lines - my $first_inst = $i; - while (($i <= $#instructions) && - ($instructions[$i]->[2] >= $first_line) && - ($instructions[$i]->[2] <= $last_line)) { - $e = $instructions[$i]; - $flat_sum{$e->[2]} += $flat_count[$i]; - $cum_sum{$e->[2]} += $cum_count[$i]; - $i++; - } - my $last_inst = $i - 1; - - # Print source lines - for (my $l = $first_line; $l <= $last_line; $l++) { - my $line = SourceLine($current_file, $l); - if (!defined($line)) { - $line = "?\n"; - next; - } else { - $line =~ s/^\s+//; - } - printf("%6s %6s %5d: %s", - UnparseAlt($flat_sum{$l}), - UnparseAlt($cum_sum{$l}), - $l, - $line); - } - - # Print disassembly - for (my $x = $first_inst; $x <= $last_inst; $x++) { - my $e = $instructions[$x]; - printf("%6s %6s %8s: %6s\n", - UnparseAlt($flat_count[$x]), - UnparseAlt($cum_count[$x]), - UnparseAddress($offset, $e->[0]), - CleanDisassembly($e->[3])); - } - } -} - -# Print DOT graph -sub PrintDot { - my $prog = shift; - my $symbols = shift; - my $raw = shift; - my $flat = shift; - my $cumulative = shift; - my $overall_total = shift; - - # Get total - my $local_total = TotalProfile($flat); - my $nodelimit = int($main::opt_nodefraction * $local_total); - my $edgelimit = int($main::opt_edgefraction * $local_total); - my $nodecount = $main::opt_nodecount; - - # Find nodes to include - my @list = (sort { abs(GetEntry($cumulative, $b)) <=> - abs(GetEntry($cumulative, $a)) - || $a cmp $b } - keys(%{$cumulative})); - my $last = $nodecount - 1; - if ($last > $#list) { - $last = $#list; - } - while (($last >= 0) && - (abs(GetEntry($cumulative, $list[$last])) <= $nodelimit)) { - $last--; - } - if ($last < 0) { - print STDERR "No nodes to print\n"; - return 0; - } - - if ($nodelimit > 0 || $edgelimit > 0) { - printf STDERR ("Dropping nodes with <= %s %s; edges with <= %s abs(%s)\n", - Unparse($nodelimit), Units(), - Unparse($edgelimit), Units()); - } - - # Open DOT output file - my $output; - my $escaped_dot = ShellEscape(@DOT); - my $escaped_ps2pdf = ShellEscape(@PS2PDF); - if ($main::opt_gv) { - my $escaped_outfile = ShellEscape(TempName($main::next_tmpfile, "ps")); - $output = "| $escaped_dot -Tps2 >$escaped_outfile"; - } elsif ($main::opt_evince) { - my $escaped_outfile = ShellEscape(TempName($main::next_tmpfile, "pdf")); - $output = "| $escaped_dot -Tps2 | $escaped_ps2pdf - $escaped_outfile"; - } elsif ($main::opt_ps) { - $output = "| $escaped_dot -Tps2"; - } elsif ($main::opt_pdf) { - $output = "| $escaped_dot -Tps2 | $escaped_ps2pdf - -"; - } elsif ($main::opt_web || $main::opt_svg) { - # We need to post-process the SVG, so write to a temporary file always. - my $escaped_outfile = ShellEscape(TempName($main::next_tmpfile, "svg")); - $output = "| $escaped_dot -Tsvg >$escaped_outfile"; - } elsif ($main::opt_gif) { - $output = "| $escaped_dot -Tgif"; - } else { - $output = ">&STDOUT"; - } - open(DOT, $output) || error("$output: $!\n"); - - # Title - printf DOT ("digraph \"%s; %s %s\" {\n", - $prog, - Unparse($overall_total), - Units()); - if ($main::opt_pdf) { - # The output is more printable if we set the page size for dot. - printf DOT ("size=\"8,11\"\n"); - } - printf DOT ("node [width=0.375,height=0.25];\n"); - - # Print legend - printf DOT ("Legend [shape=box,fontsize=24,shape=plaintext," . - "label=\"%s\\l%s\\l%s\\l%s\\l%s\\l\"];\n", - $prog, - sprintf("Total %s: %s", Units(), Unparse($overall_total)), - sprintf("Focusing on: %s", Unparse($local_total)), - sprintf("Dropped nodes with <= %s abs(%s)", - Unparse($nodelimit), Units()), - sprintf("Dropped edges with <= %s %s", - Unparse($edgelimit), Units()) - ); - - # Print nodes - my %node = (); - my $nextnode = 1; - foreach my $a (@list[0..$last]) { - # Pick font size - my $f = GetEntry($flat, $a); - my $c = GetEntry($cumulative, $a); - - my $fs = 8; - if ($local_total > 0) { - $fs = 8 + (50.0 * sqrt(abs($f * 1.0 / $local_total))); - } - - $node{$a} = $nextnode++; - my $sym = $a; - $sym =~ s/\s+/\\n/g; - $sym =~ s/::/\\n/g; - - # Extra cumulative info to print for non-leaves - my $extra = ""; - if ($f != $c) { - $extra = sprintf("\\rof %s (%s)", - Unparse($c), - Percent($c, $local_total)); - } - my $style = ""; - if ($main::opt_heapcheck) { - if ($f > 0) { - # make leak-causing nodes more visible (add a background) - $style = ",style=filled,fillcolor=gray" - } elsif ($f < 0) { - # make anti-leak-causing nodes (which almost never occur) - # stand out as well (triple border) - $style = ",peripheries=3" - } - } - - printf DOT ("N%d [label=\"%s\\n%s (%s)%s\\r" . - "\",shape=box,fontsize=%.1f%s];\n", - $node{$a}, - $sym, - Unparse($f), - Percent($f, $local_total), - $extra, - $fs, - $style, - ); - } - - # Get edges and counts per edge - my %edge = (); - my $n; - my $fullname_to_shortname_map = {}; - FillFullnameToShortnameMap($symbols, $fullname_to_shortname_map); - foreach my $k (keys(%{$raw})) { - # TODO: omit low %age edges - $n = $raw->{$k}; - my @translated = TranslateStack($symbols, $fullname_to_shortname_map, $k); - for (my $i = 1; $i <= $#translated; $i++) { - my $src = $translated[$i]; - my $dst = $translated[$i-1]; - #next if ($src eq $dst); # Avoid self-edges? - if (exists($node{$src}) && exists($node{$dst})) { - my $edge_label = "$src\001$dst"; - if (!exists($edge{$edge_label})) { - $edge{$edge_label} = 0; - } - $edge{$edge_label} += $n; - } - } - } - - # Print edges (process in order of decreasing counts) - my %indegree = (); # Number of incoming edges added per node so far - my %outdegree = (); # Number of outgoing edges added per node so far - foreach my $e (sort { $edge{$b} <=> $edge{$a} } keys(%edge)) { - my @x = split(/\001/, $e); - $n = $edge{$e}; - - # Initialize degree of kept incoming and outgoing edges if necessary - my $src = $x[0]; - my $dst = $x[1]; - if (!exists($outdegree{$src})) { $outdegree{$src} = 0; } - if (!exists($indegree{$dst})) { $indegree{$dst} = 0; } - - my $keep; - if ($indegree{$dst} == 0) { - # Keep edge if needed for reachability - $keep = 1; - } elsif (abs($n) <= $edgelimit) { - # Drop if we are below --edgefraction - $keep = 0; - } elsif ($outdegree{$src} >= $main::opt_maxdegree || - $indegree{$dst} >= $main::opt_maxdegree) { - # Keep limited number of in/out edges per node - $keep = 0; - } else { - $keep = 1; - } - - if ($keep) { - $outdegree{$src}++; - $indegree{$dst}++; - - # Compute line width based on edge count - my $fraction = abs($local_total ? (3 * ($n / $local_total)) : 0); - if ($fraction > 1) { $fraction = 1; } - my $w = $fraction * 2; - if ($w < 1 && ($main::opt_web || $main::opt_svg)) { - # SVG output treats line widths < 1 poorly. - $w = 1; - } - - # Dot sometimes segfaults if given edge weights that are too large, so - # we cap the weights at a large value - my $edgeweight = abs($n) ** 0.7; - if ($edgeweight > 100000) { $edgeweight = 100000; } - $edgeweight = int($edgeweight); - - my $style = sprintf("setlinewidth(%f)", $w); - if ($x[1] =~ m/\(inline\)/) { - $style .= ",dashed"; - } - - # Use a slightly squashed function of the edge count as the weight - printf DOT ("N%s -> N%s [label=%s, weight=%d, style=\"%s\"];\n", - $node{$x[0]}, - $node{$x[1]}, - Unparse($n), - $edgeweight, - $style); - } - } - - print DOT ("}\n"); - close(DOT); - - if ($main::opt_web || $main::opt_svg) { - # Rewrite SVG to be more usable inside web browser. - RewriteSvg(TempName($main::next_tmpfile, "svg")); - } - - return 1; -} - -sub RewriteSvg { - my $svgfile = shift; - - open(SVG, $svgfile) || die "open temp svg: $!"; - my @svg = <SVG>; - close(SVG); - unlink $svgfile; - my $svg = join('', @svg); - - # Dot's SVG output is - # - # <svg width="___" height="___" - # viewBox="___" xmlns=...> - # <g id="graph0" transform="..."> - # ... - # </g> - # </svg> - # - # Change it to - # - # <svg width="100%" height="100%" - # xmlns=...> - # $svg_javascript - # <g id="viewport" transform="translate(0,0)"> - # <g id="graph0" transform="..."> - # ... - # </g> - # </g> - # </svg> - - # Fix width, height; drop viewBox. - $svg =~ s/(?s)<svg width="[^"]+" height="[^"]+"(.*?)viewBox="[^"]+"/<svg width="100%" height="100%"$1/; - - # Insert script, viewport <g> above first <g> - my $svg_javascript = SvgJavascript(); - my $viewport = "<g id=\"viewport\" transform=\"translate(0,0)\">\n"; - $svg =~ s/<g id="graph\d"/$svg_javascript$viewport$&/; - - # Insert final </g> above </svg>. - $svg =~ s/(.*)(<\/svg>)/$1<\/g>$2/; - $svg =~ s/<g id="graph\d"(.*?)/<g id="viewport"$1/; - - if ($main::opt_svg) { - # --svg: write to standard output. - print $svg; - } else { - # Write back to temporary file. - open(SVG, ">$svgfile") || die "open $svgfile: $!"; - print SVG $svg; - close(SVG); - } -} - -sub SvgJavascript { - return <<'EOF'; -<script type="text/ecmascript"><![CDATA[ -// SVGPan -// http://www.cyberz.org/blog/2009/12/08/svgpan-a-javascript-svg-panzoomdrag-library/ -// Local modification: if(true || ...) below to force panning, never moving. - -/** - * SVGPan library 1.2 - * ==================== - * - * Given an unique existing element with id "viewport", including the - * the library into any SVG adds the following capabilities: - * - * - Mouse panning - * - Mouse zooming (using the wheel) - * - Object dargging - * - * Known issues: - * - * - Zooming (while panning) on Safari has still some issues - * - * Releases: - * - * 1.2, Sat Mar 20 08:42:50 GMT 2010, Zeng Xiaohui - * Fixed a bug with browser mouse handler interaction - * - * 1.1, Wed Feb 3 17:39:33 GMT 2010, Zeng Xiaohui - * Updated the zoom code to support the mouse wheel on Safari/Chrome - * - * 1.0, Andrea Leofreddi - * First release - * - * This code is licensed under the following BSD license: - * - * Copyright 2009-2010 Andrea Leofreddi <a.leofreddi@itcharm.com>. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, are - * permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this list of - * conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, this list - * of conditions and the following disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY Andrea Leofreddi ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND - * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL Andrea Leofreddi OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * The views and conclusions contained in the software and documentation are those of the - * authors and should not be interpreted as representing official policies, either expressed - * or implied, of Andrea Leofreddi. - */ - -var root = document.documentElement; - -var state = 'none', stateTarget, stateOrigin, stateTf; - -setupHandlers(root); - -/** - * Register handlers - */ -function setupHandlers(root){ - setAttributes(root, { - "onmouseup" : "add(evt)", - "onmousedown" : "handleMouseDown(evt)", - "onmousemove" : "handleMouseMove(evt)", - "onmouseup" : "handleMouseUp(evt)", - //"onmouseout" : "handleMouseUp(evt)", // Decomment this to stop the pan functionality when dragging out of the SVG element - }); - - if(navigator.userAgent.toLowerCase().indexOf('webkit') >= 0) - window.addEventListener('mousewheel', handleMouseWheel, false); // Chrome/Safari - else - window.addEventListener('DOMMouseScroll', handleMouseWheel, false); // Others - - var g = svgDoc.getElementById("svg"); - g.width = "100%"; - g.height = "100%"; -} - -/** - * Instance an SVGPoint object with given event coordinates. - */ -function getEventPoint(evt) { - var p = root.createSVGPoint(); - - p.x = evt.clientX; - p.y = evt.clientY; - - return p; -} - -/** - * Sets the current transform matrix of an element. - */ -function setCTM(element, matrix) { - var s = "matrix(" + matrix.a + "," + matrix.b + "," + matrix.c + "," + matrix.d + "," + matrix.e + "," + matrix.f + ")"; - - element.setAttribute("transform", s); -} - -/** - * Dumps a matrix to a string (useful for debug). - */ -function dumpMatrix(matrix) { - var s = "[ " + matrix.a + ", " + matrix.c + ", " + matrix.e + "\n " + matrix.b + ", " + matrix.d + ", " + matrix.f + "\n 0, 0, 1 ]"; - - return s; -} - -/** - * Sets attributes of an element. - */ -function setAttributes(element, attributes){ - for (i in attributes) - element.setAttributeNS(null, i, attributes[i]); -} - -/** - * Handle mouse move event. - */ -function handleMouseWheel(evt) { - if(evt.preventDefault) - evt.preventDefault(); - - evt.returnValue = false; - - var svgDoc = evt.target.ownerDocument; - - var delta; - - if(evt.wheelDelta) - delta = evt.wheelDelta / 3600; // Chrome/Safari - else - delta = evt.detail / -90; // Mozilla - - var z = 1 + delta; // Zoom factor: 0.9/1.1 - - var g = svgDoc.getElementById("viewport"); - - var p = getEventPoint(evt); - - p = p.matrixTransform(g.getCTM().inverse()); - - // Compute new scale matrix in current mouse position - var k = root.createSVGMatrix().translate(p.x, p.y).scale(z).translate(-p.x, -p.y); - - setCTM(g, g.getCTM().multiply(k)); - - stateTf = stateTf.multiply(k.inverse()); -} - -/** - * Handle mouse move event. - */ -function handleMouseMove(evt) { - if(evt.preventDefault) - evt.preventDefault(); - - evt.returnValue = false; - - var svgDoc = evt.target.ownerDocument; - - var g = svgDoc.getElementById("viewport"); - - if(state == 'pan') { - // Pan mode - var p = getEventPoint(evt).matrixTransform(stateTf); - - setCTM(g, stateTf.inverse().translate(p.x - stateOrigin.x, p.y - stateOrigin.y)); - } else if(state == 'move') { - // Move mode - var p = getEventPoint(evt).matrixTransform(g.getCTM().inverse()); - - setCTM(stateTarget, root.createSVGMatrix().translate(p.x - stateOrigin.x, p.y - stateOrigin.y).multiply(g.getCTM().inverse()).multiply(stateTarget.getCTM())); - - stateOrigin = p; - } -} - -/** - * Handle click event. - */ -function handleMouseDown(evt) { - if(evt.preventDefault) - evt.preventDefault(); - - evt.returnValue = false; - - var svgDoc = evt.target.ownerDocument; - - var g = svgDoc.getElementById("viewport"); - - if(true || evt.target.tagName == "svg") { - // Pan mode - state = 'pan'; - - stateTf = g.getCTM().inverse(); - - stateOrigin = getEventPoint(evt).matrixTransform(stateTf); - } else { - // Move mode - state = 'move'; - - stateTarget = evt.target; - - stateTf = g.getCTM().inverse(); - - stateOrigin = getEventPoint(evt).matrixTransform(stateTf); - } -} - -/** - * Handle mouse button release event. - */ -function handleMouseUp(evt) { - if(evt.preventDefault) - evt.preventDefault(); - - evt.returnValue = false; - - var svgDoc = evt.target.ownerDocument; - - if(state == 'pan' || state == 'move') { - // Quit pan mode - state = ''; - } -} - -]]></script> -EOF -} - -# Provides a map from fullname to shortname for cases where the -# shortname is ambiguous. The symlist has both the fullname and -# shortname for all symbols, which is usually fine, but sometimes -- -# such as overloaded functions -- two different fullnames can map to -# the same shortname. In that case, we use the address of the -# function to disambiguate the two. This function fills in a map that -# maps fullnames to modified shortnames in such cases. If a fullname -# is not present in the map, the 'normal' shortname provided by the -# symlist is the appropriate one to use. -sub FillFullnameToShortnameMap { - my $symbols = shift; - my $fullname_to_shortname_map = shift; - my $shortnames_seen_once = {}; - my $shortnames_seen_more_than_once = {}; - - foreach my $symlist (values(%{$symbols})) { - # TODO(csilvers): deal with inlined symbols too. - my $shortname = $symlist->[0]; - my $fullname = $symlist->[2]; - if ($fullname !~ /<[0-9a-fA-F]+>$/) { # fullname doesn't end in an address - next; # the only collisions we care about are when addresses differ - } - if (defined($shortnames_seen_once->{$shortname}) && - $shortnames_seen_once->{$shortname} ne $fullname) { - $shortnames_seen_more_than_once->{$shortname} = 1; - } else { - $shortnames_seen_once->{$shortname} = $fullname; - } - } - - foreach my $symlist (values(%{$symbols})) { - my $shortname = $symlist->[0]; - my $fullname = $symlist->[2]; - # TODO(csilvers): take in a list of addresses we care about, and only - # store in the map if $symlist->[1] is in that list. Saves space. - next if defined($fullname_to_shortname_map->{$fullname}); - if (defined($shortnames_seen_more_than_once->{$shortname})) { - if ($fullname =~ /<0*([^>]*)>$/) { # fullname has address at end of it - $fullname_to_shortname_map->{$fullname} = "$shortname\@$1"; - } - } - } -} - -# Return a small number that identifies the argument. -# Multiple calls with the same argument will return the same number. -# Calls with different arguments will return different numbers. -sub ShortIdFor { - my $key = shift; - my $id = $main::uniqueid{$key}; - if (!defined($id)) { - $id = keys(%main::uniqueid) + 1; - $main::uniqueid{$key} = $id; - } - return $id; -} - -# Translate a stack of addresses into a stack of symbols -sub TranslateStack { - my $symbols = shift; - my $fullname_to_shortname_map = shift; - my $k = shift; - - my @addrs = split(/\n/, $k); - my @result = (); - for (my $i = 0; $i <= $#addrs; $i++) { - my $a = $addrs[$i]; - - # Skip large addresses since they sometimes show up as fake entries on RH9 - if (length($a) > 8 && $a gt "7fffffffffffffff") { - next; - } - - if ($main::opt_disasm || $main::opt_list) { - # We want just the address for the key - push(@result, $a); - next; - } - - my $symlist = $symbols->{$a}; - if (!defined($symlist)) { - $symlist = [$a, "", $a]; - } - - # We can have a sequence of symbols for a particular entry - # (more than one symbol in the case of inlining). Callers - # come before callees in symlist, so walk backwards since - # the translated stack should contain callees before callers. - for (my $j = $#{$symlist}; $j >= 2; $j -= 3) { - my $func = $symlist->[$j-2]; - my $fileline = $symlist->[$j-1]; - my $fullfunc = $symlist->[$j]; - if (defined($fullname_to_shortname_map->{$fullfunc})) { - $func = $fullname_to_shortname_map->{$fullfunc}; - } - if ($j > 2) { - $func = "$func (inline)"; - } - - # Do not merge nodes corresponding to Callback::Run since that - # causes confusing cycles in dot display. Instead, we synthesize - # a unique name for this frame per caller. - if ($func =~ m/Callback.*::Run$/) { - my $caller = ($i > 0) ? $addrs[$i-1] : 0; - $func = "Run#" . ShortIdFor($caller); - } - - if ($main::opt_addresses) { - push(@result, "$a $func $fileline"); - } elsif ($main::opt_lines) { - if ($func eq '??' && $fileline eq '??:0') { - push(@result, "$a"); - } else { - push(@result, "$func $fileline"); - } - } elsif ($main::opt_functions) { - if ($func eq '??') { - push(@result, "$a"); - } else { - push(@result, $func); - } - } elsif ($main::opt_files) { - if ($fileline eq '??:0' || $fileline eq '') { - push(@result, "$a"); - } else { - my $f = $fileline; - $f =~ s/:\d+$//; - push(@result, $f); - } - } else { - push(@result, $a); - last; # Do not print inlined info - } - } - } - - # print join(",", @addrs), " => ", join(",", @result), "\n"; - return @result; -} - -# Generate percent string for a number and a total -sub Percent { - my $num = shift; - my $tot = shift; - if ($tot != 0) { - return sprintf("%.1f%%", $num * 100.0 / $tot); - } else { - return ($num == 0) ? "nan" : (($num > 0) ? "+inf" : "-inf"); - } -} - -# Generate pretty-printed form of number -sub Unparse { - my $num = shift; - if ($main::profile_type eq 'heap' || $main::profile_type eq 'growth') { - if ($main::opt_inuse_objects || $main::opt_alloc_objects) { - return sprintf("%d", $num); - } else { - if ($main::opt_show_bytes) { - return sprintf("%d", $num); - } else { - return sprintf("%.1f", $num / 1048576.0); - } - } - } elsif ($main::profile_type eq 'contention' && !$main::opt_contentions) { - return sprintf("%.3f", $num / 1e9); # Convert nanoseconds to seconds - } else { - return sprintf("%d", $num); - } -} - -# Alternate pretty-printed form: 0 maps to "." -sub UnparseAlt { - my $num = shift; - if ($num == 0) { - return "."; - } else { - return Unparse($num); - } -} - -# Alternate pretty-printed form: 0 maps to "" -sub HtmlPrintNumber { - my $num = shift; - if ($num == 0) { - return ""; - } else { - return Unparse($num); - } -} - -# Return output units -sub Units { - if ($main::profile_type eq 'heap' || $main::profile_type eq 'growth') { - if ($main::opt_inuse_objects || $main::opt_alloc_objects) { - return "objects"; - } else { - if ($main::opt_show_bytes) { - return "B"; - } else { - return "MB"; - } - } - } elsif ($main::profile_type eq 'contention' && !$main::opt_contentions) { - return "seconds"; - } else { - return "samples"; - } -} - -##### Profile manipulation code ##### - -# Generate flattened profile: -# If count is charged to stack [a,b,c,d], in generated profile, -# it will be charged to [a] -sub FlatProfile { - my $profile = shift; - my $result = {}; - foreach my $k (keys(%{$profile})) { - my $count = $profile->{$k}; - my @addrs = split(/\n/, $k); - if ($#addrs >= 0) { - AddEntry($result, $addrs[0], $count); - } - } - return $result; -} - -# Generate cumulative profile: -# If count is charged to stack [a,b,c,d], in generated profile, -# it will be charged to [a], [b], [c], [d] -sub CumulativeProfile { - my $profile = shift; - my $result = {}; - foreach my $k (keys(%{$profile})) { - my $count = $profile->{$k}; - my @addrs = split(/\n/, $k); - foreach my $a (@addrs) { - AddEntry($result, $a, $count); - } - } - return $result; -} - -# If the second-youngest PC on the stack is always the same, returns -# that pc. Otherwise, returns undef. -sub IsSecondPcAlwaysTheSame { - my $profile = shift; - - my $second_pc = undef; - foreach my $k (keys(%{$profile})) { - my @addrs = split(/\n/, $k); - if ($#addrs < 1) { - return undef; - } - if (not defined $second_pc) { - $second_pc = $addrs[1]; - } else { - if ($second_pc ne $addrs[1]) { - return undef; - } - } - } - return $second_pc; -} - -sub ExtractSymbolLocation { - my $symbols = shift; - my $address = shift; - # 'addr2line' outputs "??:0" for unknown locations; we do the - # same to be consistent. - my $location = "??:0:unknown"; - if (exists $symbols->{$address}) { - my $file = $symbols->{$address}->[1]; - if ($file eq "?") { - $file = "??:0" - } - $location = $file . ":" . $symbols->{$address}->[0]; - } - return $location; -} - -# Extracts a graph of calls. -sub ExtractCalls { - my $symbols = shift; - my $profile = shift; - - my $calls = {}; - while( my ($stack_trace, $count) = each %$profile ) { - my @address = split(/\n/, $stack_trace); - my $destination = ExtractSymbolLocation($symbols, $address[0]); - AddEntry($calls, $destination, $count); - for (my $i = 1; $i <= $#address; $i++) { - my $source = ExtractSymbolLocation($symbols, $address[$i]); - my $call = "$source -> $destination"; - AddEntry($calls, $call, $count); - $destination = $source; - } - } - - return $calls; -} - -sub FilterFrames { - my $symbols = shift; - my $profile = shift; - - if ($main::opt_retain eq '' && $main::opt_exclude eq '') { - return $profile; - } - - my $result = {}; - foreach my $k (keys(%{$profile})) { - my $count = $profile->{$k}; - my @addrs = split(/\n/, $k); - my @path = (); - foreach my $a (@addrs) { - my $sym; - if (exists($symbols->{$a})) { - $sym = $symbols->{$a}->[0]; - } else { - $sym = $a; - } - if ($main::opt_retain ne '' && $sym !~ m/$main::opt_retain/) { - next; - } - if ($main::opt_exclude ne '' && $sym =~ m/$main::opt_exclude/) { - next; - } - push(@path, $a); - } - if (scalar(@path) > 0) { - my $reduced_path = join("\n", @path); - AddEntry($result, $reduced_path, $count); - } - } - - return $result; -} - -sub RemoveUninterestingFrames { - my $symbols = shift; - my $profile = shift; - - # List of function names to skip - my %skip = (); - my $skip_regexp = 'NOMATCH'; - if ($main::profile_type eq 'heap' || $main::profile_type eq 'growth') { - foreach my $name ('@JEMALLOC_PREFIX@calloc', - 'cfree', - '@JEMALLOC_PREFIX@malloc', - 'newImpl', - 'void* newImpl', - '@JEMALLOC_PREFIX@free', - '@JEMALLOC_PREFIX@memalign', - '@JEMALLOC_PREFIX@posix_memalign', - '@JEMALLOC_PREFIX@aligned_alloc', - 'pvalloc', - '@JEMALLOC_PREFIX@valloc', - '@JEMALLOC_PREFIX@realloc', - '@JEMALLOC_PREFIX@mallocx', - '@JEMALLOC_PREFIX@rallocx', - '@JEMALLOC_PREFIX@xallocx', - '@JEMALLOC_PREFIX@dallocx', - '@JEMALLOC_PREFIX@sdallocx', - '@JEMALLOC_PREFIX@sdallocx_noflags', - 'tc_calloc', - 'tc_cfree', - 'tc_malloc', - 'tc_free', - 'tc_memalign', - 'tc_posix_memalign', - 'tc_pvalloc', - 'tc_valloc', - 'tc_realloc', - 'tc_new', - 'tc_delete', - 'tc_newarray', - 'tc_deletearray', - 'tc_new_nothrow', - 'tc_newarray_nothrow', - 'do_malloc', - '::do_malloc', # new name -- got moved to an unnamed ns - '::do_malloc_or_cpp_alloc', - 'DoSampledAllocation', - 'simple_alloc::allocate', - '__malloc_alloc_template::allocate', - '__builtin_delete', - '__builtin_new', - '__builtin_vec_delete', - '__builtin_vec_new', - 'operator new', - 'operator new[]', - # The entry to our memory-allocation routines on OS X - 'malloc_zone_malloc', - 'malloc_zone_calloc', - 'malloc_zone_valloc', - 'malloc_zone_realloc', - 'malloc_zone_memalign', - 'malloc_zone_free', - # These mark the beginning/end of our custom sections - '__start_google_malloc', - '__stop_google_malloc', - '__start_malloc_hook', - '__stop_malloc_hook') { - $skip{$name} = 1; - $skip{"_" . $name} = 1; # Mach (OS X) adds a _ prefix to everything - } - # TODO: Remove TCMalloc once everything has been - # moved into the tcmalloc:: namespace and we have flushed - # old code out of the system. - $skip_regexp = "TCMalloc|^tcmalloc::"; - } elsif ($main::profile_type eq 'contention') { - foreach my $vname ('base::RecordLockProfileData', - 'base::SubmitMutexProfileData', - 'base::SubmitSpinLockProfileData', - 'Mutex::Unlock', - 'Mutex::UnlockSlow', - 'Mutex::ReaderUnlock', - 'MutexLock::~MutexLock', - 'SpinLock::Unlock', - 'SpinLock::SlowUnlock', - 'SpinLockHolder::~SpinLockHolder') { - $skip{$vname} = 1; - } - } elsif ($main::profile_type eq 'cpu') { - # Drop signal handlers used for CPU profile collection - # TODO(dpeng): this should not be necessary; it's taken - # care of by the general 2nd-pc mechanism below. - foreach my $name ('ProfileData::Add', # historical - 'ProfileData::prof_handler', # historical - 'CpuProfiler::prof_handler', - '__FRAME_END__', - '__pthread_sighandler', - '__restore') { - $skip{$name} = 1; - } - } else { - # Nothing skipped for unknown types - } - - if ($main::profile_type eq 'cpu') { - # If all the second-youngest program counters are the same, - # this STRONGLY suggests that it is an artifact of measurement, - # i.e., stack frames pushed by the CPU profiler signal handler. - # Hence, we delete them. - # (The topmost PC is read from the signal structure, not from - # the stack, so it does not get involved.) - while (my $second_pc = IsSecondPcAlwaysTheSame($profile)) { - my $result = {}; - my $func = ''; - if (exists($symbols->{$second_pc})) { - $second_pc = $symbols->{$second_pc}->[0]; - } - print STDERR "Removing $second_pc from all stack traces.\n"; - foreach my $k (keys(%{$profile})) { - my $count = $profile->{$k}; - my @addrs = split(/\n/, $k); - splice @addrs, 1, 1; - my $reduced_path = join("\n", @addrs); - AddEntry($result, $reduced_path, $count); - } - $profile = $result; - } - } - - my $result = {}; - foreach my $k (keys(%{$profile})) { - my $count = $profile->{$k}; - my @addrs = split(/\n/, $k); - my @path = (); - foreach my $a (@addrs) { - if (exists($symbols->{$a})) { - my $func = $symbols->{$a}->[0]; - if ($skip{$func} || ($func =~ m/$skip_regexp/)) { - # Throw away the portion of the backtrace seen so far, under the - # assumption that previous frames were for functions internal to the - # allocator. - @path = (); - next; - } - } - push(@path, $a); - } - my $reduced_path = join("\n", @path); - AddEntry($result, $reduced_path, $count); - } - - $result = FilterFrames($symbols, $result); - - return $result; -} - -# Reduce profile to granularity given by user -sub ReduceProfile { - my $symbols = shift; - my $profile = shift; - my $result = {}; - my $fullname_to_shortname_map = {}; - FillFullnameToShortnameMap($symbols, $fullname_to_shortname_map); - foreach my $k (keys(%{$profile})) { - my $count = $profile->{$k}; - my @translated = TranslateStack($symbols, $fullname_to_shortname_map, $k); - my @path = (); - my %seen = (); - $seen{''} = 1; # So that empty keys are skipped - foreach my $e (@translated) { - # To avoid double-counting due to recursion, skip a stack-trace - # entry if it has already been seen - if (!$seen{$e}) { - $seen{$e} = 1; - push(@path, $e); - } - } - my $reduced_path = join("\n", @path); - AddEntry($result, $reduced_path, $count); - } - return $result; -} - -# Does the specified symbol array match the regexp? -sub SymbolMatches { - my $sym = shift; - my $re = shift; - if (defined($sym)) { - for (my $i = 0; $i < $#{$sym}; $i += 3) { - if ($sym->[$i] =~ m/$re/ || $sym->[$i+1] =~ m/$re/) { - return 1; - } - } - } - return 0; -} - -# Focus only on paths involving specified regexps -sub FocusProfile { - my $symbols = shift; - my $profile = shift; - my $focus = shift; - my $result = {}; - foreach my $k (keys(%{$profile})) { - my $count = $profile->{$k}; - my @addrs = split(/\n/, $k); - foreach my $a (@addrs) { - # Reply if it matches either the address/shortname/fileline - if (($a =~ m/$focus/) || SymbolMatches($symbols->{$a}, $focus)) { - AddEntry($result, $k, $count); - last; - } - } - } - return $result; -} - -# Focus only on paths not involving specified regexps -sub IgnoreProfile { - my $symbols = shift; - my $profile = shift; - my $ignore = shift; - my $result = {}; - foreach my $k (keys(%{$profile})) { - my $count = $profile->{$k}; - my @addrs = split(/\n/, $k); - my $matched = 0; - foreach my $a (@addrs) { - # Reply if it matches either the address/shortname/fileline - if (($a =~ m/$ignore/) || SymbolMatches($symbols->{$a}, $ignore)) { - $matched = 1; - last; - } - } - if (!$matched) { - AddEntry($result, $k, $count); - } - } - return $result; -} - -# Get total count in profile -sub TotalProfile { - my $profile = shift; - my $result = 0; - foreach my $k (keys(%{$profile})) { - $result += $profile->{$k}; - } - return $result; -} - -# Add A to B -sub AddProfile { - my $A = shift; - my $B = shift; - - my $R = {}; - # add all keys in A - foreach my $k (keys(%{$A})) { - my $v = $A->{$k}; - AddEntry($R, $k, $v); - } - # add all keys in B - foreach my $k (keys(%{$B})) { - my $v = $B->{$k}; - AddEntry($R, $k, $v); - } - return $R; -} - -# Merges symbol maps -sub MergeSymbols { - my $A = shift; - my $B = shift; - - my $R = {}; - foreach my $k (keys(%{$A})) { - $R->{$k} = $A->{$k}; - } - if (defined($B)) { - foreach my $k (keys(%{$B})) { - $R->{$k} = $B->{$k}; - } - } - return $R; -} - - -# Add A to B -sub AddPcs { - my $A = shift; - my $B = shift; - - my $R = {}; - # add all keys in A - foreach my $k (keys(%{$A})) { - $R->{$k} = 1 - } - # add all keys in B - foreach my $k (keys(%{$B})) { - $R->{$k} = 1 - } - return $R; -} - -# Subtract B from A -sub SubtractProfile { - my $A = shift; - my $B = shift; - - my $R = {}; - foreach my $k (keys(%{$A})) { - my $v = $A->{$k} - GetEntry($B, $k); - if ($v < 0 && $main::opt_drop_negative) { - $v = 0; - } - AddEntry($R, $k, $v); - } - if (!$main::opt_drop_negative) { - # Take care of when subtracted profile has more entries - foreach my $k (keys(%{$B})) { - if (!exists($A->{$k})) { - AddEntry($R, $k, 0 - $B->{$k}); - } - } - } - return $R; -} - -# Get entry from profile; zero if not present -sub GetEntry { - my $profile = shift; - my $k = shift; - if (exists($profile->{$k})) { - return $profile->{$k}; - } else { - return 0; - } -} - -# Add entry to specified profile -sub AddEntry { - my $profile = shift; - my $k = shift; - my $n = shift; - if (!exists($profile->{$k})) { - $profile->{$k} = 0; - } - $profile->{$k} += $n; -} - -# Add a stack of entries to specified profile, and add them to the $pcs -# list. -sub AddEntries { - my $profile = shift; - my $pcs = shift; - my $stack = shift; - my $count = shift; - my @k = (); - - foreach my $e (split(/\s+/, $stack)) { - my $pc = HexExtend($e); - $pcs->{$pc} = 1; - push @k, $pc; - } - AddEntry($profile, (join "\n", @k), $count); -} - -##### Code to profile a server dynamically ##### - -sub CheckSymbolPage { - my $url = SymbolPageURL(); - my $command = ShellEscape(@URL_FETCHER, $url); - open(SYMBOL, "$command |") or error($command); - my $line = <SYMBOL>; - $line =~ s/\r//g; # turn windows-looking lines into unix-looking lines - close(SYMBOL); - unless (defined($line)) { - error("$url doesn't exist\n"); - } - - if ($line =~ /^num_symbols:\s+(\d+)$/) { - if ($1 == 0) { - error("Stripped binary. No symbols available.\n"); - } - } else { - error("Failed to get the number of symbols from $url\n"); - } -} - -sub IsProfileURL { - my $profile_name = shift; - if (-f $profile_name) { - printf STDERR "Using local file $profile_name.\n"; - return 0; - } - return 1; -} - -sub ParseProfileURL { - my $profile_name = shift; - - if (!defined($profile_name) || $profile_name eq "") { - return (); - } - - # Split profile URL - matches all non-empty strings, so no test. - $profile_name =~ m,^(https?://)?([^/]+)(.*?)(/|$PROFILES)?$,; - - my $proto = $1 || "http://"; - my $hostport = $2; - my $prefix = $3; - my $profile = $4 || "/"; - - my $host = $hostport; - $host =~ s/:.*//; - - my $baseurl = "$proto$hostport$prefix"; - return ($host, $baseurl, $profile); -} - -# We fetch symbols from the first profile argument. -sub SymbolPageURL { - my ($host, $baseURL, $path) = ParseProfileURL($main::pfile_args[0]); - return "$baseURL$SYMBOL_PAGE"; -} - -sub FetchProgramName() { - my ($host, $baseURL, $path) = ParseProfileURL($main::pfile_args[0]); - my $url = "$baseURL$PROGRAM_NAME_PAGE"; - my $command_line = ShellEscape(@URL_FETCHER, $url); - open(CMDLINE, "$command_line |") or error($command_line); - my $cmdline = <CMDLINE>; - $cmdline =~ s/\r//g; # turn windows-looking lines into unix-looking lines - close(CMDLINE); - error("Failed to get program name from $url\n") unless defined($cmdline); - $cmdline =~ s/\x00.+//; # Remove argv[1] and latters. - $cmdline =~ s!\n!!g; # Remove LFs. - return $cmdline; -} - -# Gee, curl's -L (--location) option isn't reliable at least -# with its 7.12.3 version. Curl will forget to post data if -# there is a redirection. This function is a workaround for -# curl. Redirection happens on borg hosts. -sub ResolveRedirectionForCurl { - my $url = shift; - my $command_line = ShellEscape(@URL_FETCHER, "--head", $url); - open(CMDLINE, "$command_line |") or error($command_line); - while (<CMDLINE>) { - s/\r//g; # turn windows-looking lines into unix-looking lines - if (/^Location: (.*)/) { - $url = $1; - } - } - close(CMDLINE); - return $url; -} - -# Add a timeout flat to URL_FETCHER. Returns a new list. -sub AddFetchTimeout { - my $timeout = shift; - my @fetcher = @_; - if (defined($timeout)) { - if (join(" ", @fetcher) =~ m/\bcurl -s/) { - push(@fetcher, "--max-time", sprintf("%d", $timeout)); - } elsif (join(" ", @fetcher) =~ m/\brpcget\b/) { - push(@fetcher, sprintf("--deadline=%d", $timeout)); - } - } - return @fetcher; -} - -# Reads a symbol map from the file handle name given as $1, returning -# the resulting symbol map. Also processes variables relating to symbols. -# Currently, the only variable processed is 'binary=<value>' which updates -# $main::prog to have the correct program name. -sub ReadSymbols { - my $in = shift; - my $map = {}; - while (<$in>) { - s/\r//g; # turn windows-looking lines into unix-looking lines - # Removes all the leading zeroes from the symbols, see comment below. - if (m/^0x0*([0-9a-f]+)\s+(.+)/) { - $map->{$1} = $2; - } elsif (m/^---/) { - last; - } elsif (m/^([a-z][^=]*)=(.*)$/ ) { - my ($variable, $value) = ($1, $2); - for ($variable, $value) { - s/^\s+//; - s/\s+$//; - } - if ($variable eq "binary") { - if ($main::prog ne $UNKNOWN_BINARY && $main::prog ne $value) { - printf STDERR ("Warning: Mismatched binary name '%s', using '%s'.\n", - $main::prog, $value); - } - $main::prog = $value; - } else { - printf STDERR ("Ignoring unknown variable in symbols list: " . - "'%s' = '%s'\n", $variable, $value); - } - } - } - return $map; -} - -sub URLEncode { - my $str = shift; - $str =~ s/([^A-Za-z0-9\-_.!~*'()])/ sprintf "%%%02x", ord $1 /eg; - return $str; -} - -sub AppendSymbolFilterParams { - my $url = shift; - my @params = (); - if ($main::opt_retain ne '') { - push(@params, sprintf("retain=%s", URLEncode($main::opt_retain))); - } - if ($main::opt_exclude ne '') { - push(@params, sprintf("exclude=%s", URLEncode($main::opt_exclude))); - } - if (scalar @params > 0) { - $url = sprintf("%s?%s", $url, join("&", @params)); - } - return $url; -} - -# Fetches and processes symbols to prepare them for use in the profile output -# code. If the optional 'symbol_map' arg is not given, fetches symbols from -# $SYMBOL_PAGE for all PC values found in profile. Otherwise, the raw symbols -# are assumed to have already been fetched into 'symbol_map' and are simply -# extracted and processed. -sub FetchSymbols { - my $pcset = shift; - my $symbol_map = shift; - - my %seen = (); - my @pcs = grep { !$seen{$_}++ } keys(%$pcset); # uniq - - if (!defined($symbol_map)) { - my $post_data = join("+", sort((map {"0x" . "$_"} @pcs))); - - open(POSTFILE, ">$main::tmpfile_sym"); - print POSTFILE $post_data; - close(POSTFILE); - - my $url = SymbolPageURL(); - - my $command_line; - if (join(" ", @URL_FETCHER) =~ m/\bcurl -s/) { - $url = ResolveRedirectionForCurl($url); - $url = AppendSymbolFilterParams($url); - $command_line = ShellEscape(@URL_FETCHER, "-d", "\@$main::tmpfile_sym", - $url); - } else { - $url = AppendSymbolFilterParams($url); - $command_line = (ShellEscape(@URL_FETCHER, "--post", $url) - . " < " . ShellEscape($main::tmpfile_sym)); - } - # We use c++filt in case $SYMBOL_PAGE gives us mangled symbols. - my $escaped_cppfilt = ShellEscape($obj_tool_map{"c++filt"}); - open(SYMBOL, "$command_line | $escaped_cppfilt |") or error($command_line); - $symbol_map = ReadSymbols(*SYMBOL{IO}); - close(SYMBOL); - } - - my $symbols = {}; - foreach my $pc (@pcs) { - my $fullname; - # For 64 bits binaries, symbols are extracted with 8 leading zeroes. - # Then /symbol reads the long symbols in as uint64, and outputs - # the result with a "0x%08llx" format which get rid of the zeroes. - # By removing all the leading zeroes in both $pc and the symbols from - # /symbol, the symbols match and are retrievable from the map. - my $shortpc = $pc; - $shortpc =~ s/^0*//; - # Each line may have a list of names, which includes the function - # and also other functions it has inlined. They are separated (in - # PrintSymbolizedProfile), by --, which is illegal in function names. - my $fullnames; - if (defined($symbol_map->{$shortpc})) { - $fullnames = $symbol_map->{$shortpc}; - } else { - $fullnames = "0x" . $pc; # Just use addresses - } - my $sym = []; - $symbols->{$pc} = $sym; - foreach my $fullname (split("--", $fullnames)) { - my $name = ShortFunctionName($fullname); - push(@{$sym}, $name, "?", $fullname); - } - } - return $symbols; -} - -sub BaseName { - my $file_name = shift; - $file_name =~ s!^.*/!!; # Remove directory name - return $file_name; -} - -sub MakeProfileBaseName { - my ($binary_name, $profile_name) = @_; - my ($host, $baseURL, $path) = ParseProfileURL($profile_name); - my $binary_shortname = BaseName($binary_name); - return sprintf("%s.%s.%s", - $binary_shortname, $main::op_time, $host); -} - -sub FetchDynamicProfile { - my $binary_name = shift; - my $profile_name = shift; - my $fetch_name_only = shift; - my $encourage_patience = shift; - - if (!IsProfileURL($profile_name)) { - return $profile_name; - } else { - my ($host, $baseURL, $path) = ParseProfileURL($profile_name); - if ($path eq "" || $path eq "/") { - # Missing type specifier defaults to cpu-profile - $path = $PROFILE_PAGE; - } - - my $profile_file = MakeProfileBaseName($binary_name, $profile_name); - - my $url = "$baseURL$path"; - my $fetch_timeout = undef; - if ($path =~ m/$PROFILE_PAGE|$PMUPROFILE_PAGE/) { - if ($path =~ m/[?]/) { - $url .= "&"; - } else { - $url .= "?"; - } - $url .= sprintf("seconds=%d", $main::opt_seconds); - $fetch_timeout = $main::opt_seconds * 1.01 + 60; - # Set $profile_type for consumption by PrintSymbolizedProfile. - $main::profile_type = 'cpu'; - } else { - # For non-CPU profiles, we add a type-extension to - # the target profile file name. - my $suffix = $path; - $suffix =~ s,/,.,g; - $profile_file .= $suffix; - # Set $profile_type for consumption by PrintSymbolizedProfile. - if ($path =~ m/$HEAP_PAGE/) { - $main::profile_type = 'heap'; - } elsif ($path =~ m/$GROWTH_PAGE/) { - $main::profile_type = 'growth'; - } elsif ($path =~ m/$CONTENTION_PAGE/) { - $main::profile_type = 'contention'; - } - } - - my $profile_dir = $ENV{"JEPROF_TMPDIR"} || ($ENV{HOME} . "/jeprof"); - if (! -d $profile_dir) { - mkdir($profile_dir) - || die("Unable to create profile directory $profile_dir: $!\n"); - } - my $tmp_profile = "$profile_dir/.tmp.$profile_file"; - my $real_profile = "$profile_dir/$profile_file"; - - if ($fetch_name_only > 0) { - return $real_profile; - } - - my @fetcher = AddFetchTimeout($fetch_timeout, @URL_FETCHER); - my $cmd = ShellEscape(@fetcher, $url) . " > " . ShellEscape($tmp_profile); - if ($path =~ m/$PROFILE_PAGE|$PMUPROFILE_PAGE|$CENSUSPROFILE_PAGE/){ - print STDERR "Gathering CPU profile from $url for $main::opt_seconds seconds to\n ${real_profile}\n"; - if ($encourage_patience) { - print STDERR "Be patient...\n"; - } - } else { - print STDERR "Fetching $path profile from $url to\n ${real_profile}\n"; - } - - (system($cmd) == 0) || error("Failed to get profile: $cmd: $!\n"); - (system("mv", $tmp_profile, $real_profile) == 0) || error("Unable to rename profile\n"); - print STDERR "Wrote profile to $real_profile\n"; - $main::collected_profile = $real_profile; - return $main::collected_profile; - } -} - -# Collect profiles in parallel -sub FetchDynamicProfiles { - my $items = scalar(@main::pfile_args); - my $levels = log($items) / log(2); - - if ($items == 1) { - $main::profile_files[0] = FetchDynamicProfile($main::prog, $main::pfile_args[0], 0, 1); - } else { - # math rounding issues - if ((2 ** $levels) < $items) { - $levels++; - } - my $count = scalar(@main::pfile_args); - for (my $i = 0; $i < $count; $i++) { - $main::profile_files[$i] = FetchDynamicProfile($main::prog, $main::pfile_args[$i], 1, 0); - } - print STDERR "Fetching $count profiles, Be patient...\n"; - FetchDynamicProfilesRecurse($levels, 0, 0); - $main::collected_profile = join(" \\\n ", @main::profile_files); - } -} - -# Recursively fork a process to get enough processes -# collecting profiles -sub FetchDynamicProfilesRecurse { - my $maxlevel = shift; - my $level = shift; - my $position = shift; - - if (my $pid = fork()) { - $position = 0 | ($position << 1); - TryCollectProfile($maxlevel, $level, $position); - wait; - } else { - $position = 1 | ($position << 1); - TryCollectProfile($maxlevel, $level, $position); - cleanup(); - exit(0); - } -} - -# Collect a single profile -sub TryCollectProfile { - my $maxlevel = shift; - my $level = shift; - my $position = shift; - - if ($level >= ($maxlevel - 1)) { - if ($position < scalar(@main::pfile_args)) { - FetchDynamicProfile($main::prog, $main::pfile_args[$position], 0, 0); - } - } else { - FetchDynamicProfilesRecurse($maxlevel, $level+1, $position); - } -} - -##### Parsing code ##### - -# Provide a small streaming-read module to handle very large -# cpu-profile files. Stream in chunks along a sliding window. -# Provides an interface to get one 'slot', correctly handling -# endian-ness differences. A slot is one 32-bit or 64-bit word -# (depending on the input profile). We tell endianness and bit-size -# for the profile by looking at the first 8 bytes: in cpu profiles, -# the second slot is always 3 (we'll accept anything that's not 0). -BEGIN { - package CpuProfileStream; - - sub new { - my ($class, $file, $fname) = @_; - my $self = { file => $file, - base => 0, - stride => 512 * 1024, # must be a multiple of bitsize/8 - slots => [], - unpack_code => "", # N for big-endian, V for little - perl_is_64bit => 1, # matters if profile is 64-bit - }; - bless $self, $class; - # Let unittests adjust the stride - if ($main::opt_test_stride > 0) { - $self->{stride} = $main::opt_test_stride; - } - # Read the first two slots to figure out bitsize and endianness. - my $slots = $self->{slots}; - my $str; - read($self->{file}, $str, 8); - # Set the global $address_length based on what we see here. - # 8 is 32-bit (8 hexadecimal chars); 16 is 64-bit (16 hexadecimal chars). - $address_length = ($str eq (chr(0)x8)) ? 16 : 8; - if ($address_length == 8) { - if (substr($str, 6, 2) eq chr(0)x2) { - $self->{unpack_code} = 'V'; # Little-endian. - } elsif (substr($str, 4, 2) eq chr(0)x2) { - $self->{unpack_code} = 'N'; # Big-endian - } else { - ::error("$fname: header size >= 2**16\n"); - } - @$slots = unpack($self->{unpack_code} . "*", $str); - } else { - # If we're a 64-bit profile, check if we're a 64-bit-capable - # perl. Otherwise, each slot will be represented as a float - # instead of an int64, losing precision and making all the - # 64-bit addresses wrong. We won't complain yet, but will - # later if we ever see a value that doesn't fit in 32 bits. - my $has_q = 0; - eval { $has_q = pack("Q", "1") ? 1 : 1; }; - if (!$has_q) { - $self->{perl_is_64bit} = 0; - } - read($self->{file}, $str, 8); - if (substr($str, 4, 4) eq chr(0)x4) { - # We'd love to use 'Q', but it's a) not universal, b) not endian-proof. - $self->{unpack_code} = 'V'; # Little-endian. - } elsif (substr($str, 0, 4) eq chr(0)x4) { - $self->{unpack_code} = 'N'; # Big-endian - } else { - ::error("$fname: header size >= 2**32\n"); - } - my @pair = unpack($self->{unpack_code} . "*", $str); - # Since we know one of the pair is 0, it's fine to just add them. - @$slots = (0, $pair[0] + $pair[1]); - } - return $self; - } - - # Load more data when we access slots->get(X) which is not yet in memory. - sub overflow { - my ($self) = @_; - my $slots = $self->{slots}; - $self->{base} += $#$slots + 1; # skip over data we're replacing - my $str; - read($self->{file}, $str, $self->{stride}); - if ($address_length == 8) { # the 32-bit case - # This is the easy case: unpack provides 32-bit unpacking primitives. - @$slots = unpack($self->{unpack_code} . "*", $str); - } else { - # We need to unpack 32 bits at a time and combine. - my @b32_values = unpack($self->{unpack_code} . "*", $str); - my @b64_values = (); - for (my $i = 0; $i < $#b32_values; $i += 2) { - # TODO(csilvers): if this is a 32-bit perl, the math below - # could end up in a too-large int, which perl will promote - # to a double, losing necessary precision. Deal with that. - # Right now, we just die. - my ($lo, $hi) = ($b32_values[$i], $b32_values[$i+1]); - if ($self->{unpack_code} eq 'N') { # big-endian - ($lo, $hi) = ($hi, $lo); - } - my $value = $lo + $hi * (2**32); - if (!$self->{perl_is_64bit} && # check value is exactly represented - (($value % (2**32)) != $lo || int($value / (2**32)) != $hi)) { - ::error("Need a 64-bit perl to process this 64-bit profile.\n"); - } - push(@b64_values, $value); - } - @$slots = @b64_values; - } - } - - # Access the i-th long in the file (logically), or -1 at EOF. - sub get { - my ($self, $idx) = @_; - my $slots = $self->{slots}; - while ($#$slots >= 0) { - if ($idx < $self->{base}) { - # The only time we expect a reference to $slots[$i - something] - # after referencing $slots[$i] is reading the very first header. - # Since $stride > |header|, that shouldn't cause any lookback - # errors. And everything after the header is sequential. - print STDERR "Unexpected look-back reading CPU profile"; - return -1; # shrug, don't know what better to return - } elsif ($idx > $self->{base} + $#$slots) { - $self->overflow(); - } else { - return $slots->[$idx - $self->{base}]; - } - } - # If we get here, $slots is [], which means we've reached EOF - return -1; # unique since slots is supposed to hold unsigned numbers - } -} - -# Reads the top, 'header' section of a profile, and returns the last -# line of the header, commonly called a 'header line'. The header -# section of a profile consists of zero or more 'command' lines that -# are instructions to jeprof, which jeprof executes when reading the -# header. All 'command' lines start with a %. After the command -# lines is the 'header line', which is a profile-specific line that -# indicates what type of profile it is, and perhaps other global -# information about the profile. For instance, here's a header line -# for a heap profile: -# heap profile: 53: 38236 [ 5525: 1284029] @ heapprofile -# For historical reasons, the CPU profile does not contain a text- -# readable header line. If the profile looks like a CPU profile, -# this function returns "". If no header line could be found, this -# function returns undef. -# -# The following commands are recognized: -# %warn -- emit the rest of this line to stderr, prefixed by 'WARNING:' -# -# The input file should be in binmode. -sub ReadProfileHeader { - local *PROFILE = shift; - my $firstchar = ""; - my $line = ""; - read(PROFILE, $firstchar, 1); - seek(PROFILE, -1, 1); # unread the firstchar - if ($firstchar !~ /[[:print:]]/) { # is not a text character - return ""; - } - while (defined($line = <PROFILE>)) { - $line =~ s/\r//g; # turn windows-looking lines into unix-looking lines - if ($line =~ /^%warn\s+(.*)/) { # 'warn' command - # Note this matches both '%warn blah\n' and '%warn\n'. - print STDERR "WARNING: $1\n"; # print the rest of the line - } elsif ($line =~ /^%/) { - print STDERR "Ignoring unknown command from profile header: $line"; - } else { - # End of commands, must be the header line. - return $line; - } - } - return undef; # got to EOF without seeing a header line -} - -sub IsSymbolizedProfileFile { - my $file_name = shift; - if (!(-e $file_name) || !(-r $file_name)) { - return 0; - } - # Check if the file contains a symbol-section marker. - open(TFILE, "<$file_name"); - binmode TFILE; - my $firstline = ReadProfileHeader(*TFILE); - close(TFILE); - if (!$firstline) { - return 0; - } - $SYMBOL_PAGE =~ m,[^/]+$,; # matches everything after the last slash - my $symbol_marker = $&; - return $firstline =~ /^--- *$symbol_marker/; -} - -# Parse profile generated by common/profiler.cc and return a reference -# to a map: -# $result->{version} Version number of profile file -# $result->{period} Sampling period (in microseconds) -# $result->{profile} Profile object -# $result->{threads} Map of thread IDs to profile objects -# $result->{map} Memory map info from profile -# $result->{pcs} Hash of all PC values seen, key is hex address -sub ReadProfile { - my $prog = shift; - my $fname = shift; - my $result; # return value - - $CONTENTION_PAGE =~ m,[^/]+$,; # matches everything after the last slash - my $contention_marker = $&; - $GROWTH_PAGE =~ m,[^/]+$,; # matches everything after the last slash - my $growth_marker = $&; - $SYMBOL_PAGE =~ m,[^/]+$,; # matches everything after the last slash - my $symbol_marker = $&; - $PROFILE_PAGE =~ m,[^/]+$,; # matches everything after the last slash - my $profile_marker = $&; - $HEAP_PAGE =~ m,[^/]+$,; # matches everything after the last slash - my $heap_marker = $&; - - # Look at first line to see if it is a heap or a CPU profile. - # CPU profile may start with no header at all, and just binary data - # (starting with \0\0\0\0) -- in that case, don't try to read the - # whole firstline, since it may be gigabytes(!) of data. - open(PROFILE, "<$fname") || error("$fname: $!\n"); - binmode PROFILE; # New perls do UTF-8 processing - my $header = ReadProfileHeader(*PROFILE); - if (!defined($header)) { # means "at EOF" - error("Profile is empty.\n"); - } - - my $symbols; - if ($header =~ m/^--- *$symbol_marker/o) { - # Verify that the user asked for a symbolized profile - if (!$main::use_symbolized_profile) { - # we have both a binary and symbolized profiles, abort - error("FATAL ERROR: Symbolized profile\n $fname\ncannot be used with " . - "a binary arg. Try again without passing\n $prog\n"); - } - # Read the symbol section of the symbolized profile file. - $symbols = ReadSymbols(*PROFILE{IO}); - # Read the next line to get the header for the remaining profile. - $header = ReadProfileHeader(*PROFILE) || ""; - } - - if ($header =~ m/^--- *($heap_marker|$growth_marker)/o) { - # Skip "--- ..." line for profile types that have their own headers. - $header = ReadProfileHeader(*PROFILE) || ""; - } - - $main::profile_type = ''; - - if ($header =~ m/^heap profile:.*$growth_marker/o) { - $main::profile_type = 'growth'; - $result = ReadHeapProfile($prog, *PROFILE, $header); - } elsif ($header =~ m/^heap profile:/) { - $main::profile_type = 'heap'; - $result = ReadHeapProfile($prog, *PROFILE, $header); - } elsif ($header =~ m/^heap/) { - $main::profile_type = 'heap'; - $result = ReadThreadedHeapProfile($prog, $fname, $header); - } elsif ($header =~ m/^--- *$contention_marker/o) { - $main::profile_type = 'contention'; - $result = ReadSynchProfile($prog, *PROFILE); - } elsif ($header =~ m/^--- *Stacks:/) { - print STDERR - "Old format contention profile: mistakenly reports " . - "condition variable signals as lock contentions.\n"; - $main::profile_type = 'contention'; - $result = ReadSynchProfile($prog, *PROFILE); - } elsif ($header =~ m/^--- *$profile_marker/) { - # the binary cpu profile data starts immediately after this line - $main::profile_type = 'cpu'; - $result = ReadCPUProfile($prog, $fname, *PROFILE); - } else { - if (defined($symbols)) { - # a symbolized profile contains a format we don't recognize, bail out - error("$fname: Cannot recognize profile section after symbols.\n"); - } - # no ascii header present -- must be a CPU profile - $main::profile_type = 'cpu'; - $result = ReadCPUProfile($prog, $fname, *PROFILE); - } - - close(PROFILE); - - # if we got symbols along with the profile, return those as well - if (defined($symbols)) { - $result->{symbols} = $symbols; - } - - return $result; -} - -# Subtract one from caller pc so we map back to call instr. -# However, don't do this if we're reading a symbolized profile -# file, in which case the subtract-one was done when the file -# was written. -# -# We apply the same logic to all readers, though ReadCPUProfile uses an -# independent implementation. -sub FixCallerAddresses { - my $stack = shift; - # --raw/http: Always subtract one from pc's, because PrintSymbolizedProfile() - # dumps unadjusted profiles. - { - $stack =~ /(\s)/; - my $delimiter = $1; - my @addrs = split(' ', $stack); - my @fixedaddrs; - $#fixedaddrs = $#addrs; - if ($#addrs >= 0) { - $fixedaddrs[0] = $addrs[0]; - } - for (my $i = 1; $i <= $#addrs; $i++) { - $fixedaddrs[$i] = AddressSub($addrs[$i], "0x1"); - } - return join $delimiter, @fixedaddrs; - } -} - -# CPU profile reader -sub ReadCPUProfile { - my $prog = shift; - my $fname = shift; # just used for logging - local *PROFILE = shift; - my $version; - my $period; - my $i; - my $profile = {}; - my $pcs = {}; - - # Parse string into array of slots. - my $slots = CpuProfileStream->new(*PROFILE, $fname); - - # Read header. The current header version is a 5-element structure - # containing: - # 0: header count (always 0) - # 1: header "words" (after this one: 3) - # 2: format version (0) - # 3: sampling period (usec) - # 4: unused padding (always 0) - if ($slots->get(0) != 0 ) { - error("$fname: not a profile file, or old format profile file\n"); - } - $i = 2 + $slots->get(1); - $version = $slots->get(2); - $period = $slots->get(3); - # Do some sanity checking on these header values. - if ($version > (2**32) || $period > (2**32) || $i > (2**32) || $i < 5) { - error("$fname: not a profile file, or corrupted profile file\n"); - } - - # Parse profile - while ($slots->get($i) != -1) { - my $n = $slots->get($i++); - my $d = $slots->get($i++); - if ($d > (2**16)) { # TODO(csilvers): what's a reasonable max-stack-depth? - my $addr = sprintf("0%o", $i * ($address_length == 8 ? 4 : 8)); - print STDERR "At index $i (address $addr):\n"; - error("$fname: stack trace depth >= 2**32\n"); - } - if ($slots->get($i) == 0) { - # End of profile data marker - $i += $d; - last; - } - - # Make key out of the stack entries - my @k = (); - for (my $j = 0; $j < $d; $j++) { - my $pc = $slots->get($i+$j); - # Subtract one from caller pc so we map back to call instr. - $pc--; - $pc = sprintf("%0*x", $address_length, $pc); - $pcs->{$pc} = 1; - push @k, $pc; - } - - AddEntry($profile, (join "\n", @k), $n); - $i += $d; - } - - # Parse map - my $map = ''; - seek(PROFILE, $i * 4, 0); - read(PROFILE, $map, (stat PROFILE)[7]); - - my $r = {}; - $r->{version} = $version; - $r->{period} = $period; - $r->{profile} = $profile; - $r->{libs} = ParseLibraries($prog, $map, $pcs); - $r->{pcs} = $pcs; - - return $r; -} - -sub HeapProfileIndex { - my $index = 1; - if ($main::opt_inuse_space) { - $index = 1; - } elsif ($main::opt_inuse_objects) { - $index = 0; - } elsif ($main::opt_alloc_space) { - $index = 3; - } elsif ($main::opt_alloc_objects) { - $index = 2; - } - return $index; -} - -sub ReadMappedLibraries { - my $fh = shift; - my $map = ""; - # Read the /proc/self/maps data - while (<$fh>) { - s/\r//g; # turn windows-looking lines into unix-looking lines - $map .= $_; - } - return $map; -} - -sub ReadMemoryMap { - my $fh = shift; - my $map = ""; - # Read /proc/self/maps data as formatted by DumpAddressMap() - my $buildvar = ""; - while (<PROFILE>) { - s/\r//g; # turn windows-looking lines into unix-looking lines - # Parse "build=<dir>" specification if supplied - if (m/^\s*build=(.*)\n/) { - $buildvar = $1; - } - - # Expand "$build" variable if available - $_ =~ s/\$build\b/$buildvar/g; - - $map .= $_; - } - return $map; -} - -sub AdjustSamples { - my ($sample_adjustment, $sampling_algorithm, $n1, $s1, $n2, $s2) = @_; - if ($sample_adjustment) { - if ($sampling_algorithm == 2) { - # Remote-heap version 2 - # The sampling frequency is the rate of a Poisson process. - # This means that the probability of sampling an allocation of - # size X with sampling rate Y is 1 - exp(-X/Y) - if ($n1 != 0) { - my $ratio = (($s1*1.0)/$n1)/($sample_adjustment); - my $scale_factor = 1/(1 - exp(-$ratio)); - $n1 *= $scale_factor; - $s1 *= $scale_factor; - } - if ($n2 != 0) { - my $ratio = (($s2*1.0)/$n2)/($sample_adjustment); - my $scale_factor = 1/(1 - exp(-$ratio)); - $n2 *= $scale_factor; - $s2 *= $scale_factor; - } - } else { - # Remote-heap version 1 - my $ratio; - $ratio = (($s1*1.0)/$n1)/($sample_adjustment); - if ($ratio < 1) { - $n1 /= $ratio; - $s1 /= $ratio; - } - $ratio = (($s2*1.0)/$n2)/($sample_adjustment); - if ($ratio < 1) { - $n2 /= $ratio; - $s2 /= $ratio; - } - } - } - return ($n1, $s1, $n2, $s2); -} - -sub ReadHeapProfile { - my $prog = shift; - local *PROFILE = shift; - my $header = shift; - - my $index = HeapProfileIndex(); - - # Find the type of this profile. The header line looks like: - # heap profile: 1246: 8800744 [ 1246: 8800744] @ <heap-url>/266053 - # There are two pairs <count: size>, the first inuse objects/space, and the - # second allocated objects/space. This is followed optionally by a profile - # type, and if that is present, optionally by a sampling frequency. - # For remote heap profiles (v1): - # The interpretation of the sampling frequency is that the profiler, for - # each sample, calculates a uniformly distributed random integer less than - # the given value, and records the next sample after that many bytes have - # been allocated. Therefore, the expected sample interval is half of the - # given frequency. By default, if not specified, the expected sample - # interval is 128KB. Only remote-heap-page profiles are adjusted for - # sample size. - # For remote heap profiles (v2): - # The sampling frequency is the rate of a Poisson process. This means that - # the probability of sampling an allocation of size X with sampling rate Y - # is 1 - exp(-X/Y) - # For version 2, a typical header line might look like this: - # heap profile: 1922: 127792360 [ 1922: 127792360] @ <heap-url>_v2/524288 - # the trailing number (524288) is the sampling rate. (Version 1 showed - # double the 'rate' here) - my $sampling_algorithm = 0; - my $sample_adjustment = 0; - chomp($header); - my $type = "unknown"; - if ($header =~ m"^heap profile:\s*(\d+):\s+(\d+)\s+\[\s*(\d+):\s+(\d+)\](\s*@\s*([^/]*)(/(\d+))?)?") { - if (defined($6) && ($6 ne '')) { - $type = $6; - my $sample_period = $8; - # $type is "heapprofile" for profiles generated by the - # heap-profiler, and either "heap" or "heap_v2" for profiles - # generated by sampling directly within tcmalloc. It can also - # be "growth" for heap-growth profiles. The first is typically - # found for profiles generated locally, and the others for - # remote profiles. - if (($type eq "heapprofile") || ($type !~ /heap/) ) { - # No need to adjust for the sampling rate with heap-profiler-derived data - $sampling_algorithm = 0; - } elsif ($type =~ /_v2/) { - $sampling_algorithm = 2; # version 2 sampling - if (defined($sample_period) && ($sample_period ne '')) { - $sample_adjustment = int($sample_period); - } - } else { - $sampling_algorithm = 1; # version 1 sampling - if (defined($sample_period) && ($sample_period ne '')) { - $sample_adjustment = int($sample_period)/2; - } - } - } else { - # We detect whether or not this is a remote-heap profile by checking - # that the total-allocated stats ($n2,$s2) are exactly the - # same as the in-use stats ($n1,$s1). It is remotely conceivable - # that a non-remote-heap profile may pass this check, but it is hard - # to imagine how that could happen. - # In this case it's so old it's guaranteed to be remote-heap version 1. - my ($n1, $s1, $n2, $s2) = ($1, $2, $3, $4); - if (($n1 == $n2) && ($s1 == $s2)) { - # This is likely to be a remote-heap based sample profile - $sampling_algorithm = 1; - } - } - } - - if ($sampling_algorithm > 0) { - # For remote-heap generated profiles, adjust the counts and sizes to - # account for the sample rate (we sample once every 128KB by default). - if ($sample_adjustment == 0) { - # Turn on profile adjustment. - $sample_adjustment = 128*1024; - print STDERR "Adjusting heap profiles for 1-in-128KB sampling rate\n"; - } else { - printf STDERR ("Adjusting heap profiles for 1-in-%d sampling rate\n", - $sample_adjustment); - } - if ($sampling_algorithm > 1) { - # We don't bother printing anything for the original version (version 1) - printf STDERR "Heap version $sampling_algorithm\n"; - } - } - - my $profile = {}; - my $pcs = {}; - my $map = ""; - - while (<PROFILE>) { - s/\r//g; # turn windows-looking lines into unix-looking lines - if (/^MAPPED_LIBRARIES:/) { - $map .= ReadMappedLibraries(*PROFILE); - last; - } - - if (/^--- Memory map:/) { - $map .= ReadMemoryMap(*PROFILE); - last; - } - - # Read entry of the form: - # <count1>: <bytes1> [<count2>: <bytes2>] @ a1 a2 a3 ... an - s/^\s*//; - s/\s*$//; - if (m/^\s*(\d+):\s+(\d+)\s+\[\s*(\d+):\s+(\d+)\]\s+@\s+(.*)$/) { - my $stack = $5; - my ($n1, $s1, $n2, $s2) = ($1, $2, $3, $4); - my @counts = AdjustSamples($sample_adjustment, $sampling_algorithm, - $n1, $s1, $n2, $s2); - AddEntries($profile, $pcs, FixCallerAddresses($stack), $counts[$index]); - } - } - - my $r = {}; - $r->{version} = "heap"; - $r->{period} = 1; - $r->{profile} = $profile; - $r->{libs} = ParseLibraries($prog, $map, $pcs); - $r->{pcs} = $pcs; - return $r; -} - -sub ReadThreadedHeapProfile { - my ($prog, $fname, $header) = @_; - - my $index = HeapProfileIndex(); - my $sampling_algorithm = 0; - my $sample_adjustment = 0; - chomp($header); - my $type = "unknown"; - # Assuming a very specific type of header for now. - if ($header =~ m"^heap_v2/(\d+)") { - $type = "_v2"; - $sampling_algorithm = 2; - $sample_adjustment = int($1); - } - if ($type ne "_v2" || !defined($sample_adjustment)) { - die "Threaded heap profiles require v2 sampling with a sample rate\n"; - } - - my $profile = {}; - my $thread_profiles = {}; - my $pcs = {}; - my $map = ""; - my $stack = ""; - - while (<PROFILE>) { - s/\r//g; - if (/^MAPPED_LIBRARIES:/) { - $map .= ReadMappedLibraries(*PROFILE); - last; - } - - if (/^--- Memory map:/) { - $map .= ReadMemoryMap(*PROFILE); - last; - } - - # Read entry of the form: - # @ a1 a2 ... an - # t*: <count1>: <bytes1> [<count2>: <bytes2>] - # t1: <count1>: <bytes1> [<count2>: <bytes2>] - # ... - # tn: <count1>: <bytes1> [<count2>: <bytes2>] - s/^\s*//; - s/\s*$//; - if (m/^@\s+(.*)$/) { - $stack = $1; - } elsif (m/^\s*(t(\*|\d+)):\s+(\d+):\s+(\d+)\s+\[\s*(\d+):\s+(\d+)\]$/) { - if ($stack eq "") { - # Still in the header, so this is just a per-thread summary. - next; - } - my $thread = $2; - my ($n1, $s1, $n2, $s2) = ($3, $4, $5, $6); - my @counts = AdjustSamples($sample_adjustment, $sampling_algorithm, - $n1, $s1, $n2, $s2); - if ($thread eq "*") { - AddEntries($profile, $pcs, FixCallerAddresses($stack), $counts[$index]); - } else { - if (!exists($thread_profiles->{$thread})) { - $thread_profiles->{$thread} = {}; - } - AddEntries($thread_profiles->{$thread}, $pcs, - FixCallerAddresses($stack), $counts[$index]); - } - } - } - - my $r = {}; - $r->{version} = "heap"; - $r->{period} = 1; - $r->{profile} = $profile; - $r->{threads} = $thread_profiles; - $r->{libs} = ParseLibraries($prog, $map, $pcs); - $r->{pcs} = $pcs; - return $r; -} - -sub ReadSynchProfile { - my $prog = shift; - local *PROFILE = shift; - my $header = shift; - - my $map = ''; - my $profile = {}; - my $pcs = {}; - my $sampling_period = 1; - my $cyclespernanosec = 2.8; # Default assumption for old binaries - my $seen_clockrate = 0; - my $line; - - my $index = 0; - if ($main::opt_total_delay) { - $index = 0; - } elsif ($main::opt_contentions) { - $index = 1; - } elsif ($main::opt_mean_delay) { - $index = 2; - } - - while ( $line = <PROFILE> ) { - $line =~ s/\r//g; # turn windows-looking lines into unix-looking lines - if ( $line =~ /^\s*(\d+)\s+(\d+) \@\s*(.*?)\s*$/ ) { - my ($cycles, $count, $stack) = ($1, $2, $3); - - # Convert cycles to nanoseconds - $cycles /= $cyclespernanosec; - - # Adjust for sampling done by application - $cycles *= $sampling_period; - $count *= $sampling_period; - - my @values = ($cycles, $count, $cycles / $count); - AddEntries($profile, $pcs, FixCallerAddresses($stack), $values[$index]); - - } elsif ( $line =~ /^(slow release).*thread \d+ \@\s*(.*?)\s*$/ || - $line =~ /^\s*(\d+) \@\s*(.*?)\s*$/ ) { - my ($cycles, $stack) = ($1, $2); - if ($cycles !~ /^\d+$/) { - next; - } - - # Convert cycles to nanoseconds - $cycles /= $cyclespernanosec; - - # Adjust for sampling done by application - $cycles *= $sampling_period; - - AddEntries($profile, $pcs, FixCallerAddresses($stack), $cycles); - - } elsif ( $line =~ m/^([a-z][^=]*)=(.*)$/ ) { - my ($variable, $value) = ($1,$2); - for ($variable, $value) { - s/^\s+//; - s/\s+$//; - } - if ($variable eq "cycles/second") { - $cyclespernanosec = $value / 1e9; - $seen_clockrate = 1; - } elsif ($variable eq "sampling period") { - $sampling_period = $value; - } elsif ($variable eq "ms since reset") { - # Currently nothing is done with this value in jeprof - # So we just silently ignore it for now - } elsif ($variable eq "discarded samples") { - # Currently nothing is done with this value in jeprof - # So we just silently ignore it for now - } else { - printf STDERR ("Ignoring unnknown variable in /contention output: " . - "'%s' = '%s'\n",$variable,$value); - } - } else { - # Memory map entry - $map .= $line; - } - } - - if (!$seen_clockrate) { - printf STDERR ("No cycles/second entry in profile; Guessing %.1f GHz\n", - $cyclespernanosec); - } - - my $r = {}; - $r->{version} = 0; - $r->{period} = $sampling_period; - $r->{profile} = $profile; - $r->{libs} = ParseLibraries($prog, $map, $pcs); - $r->{pcs} = $pcs; - return $r; -} - -# Given a hex value in the form "0x1abcd" or "1abcd", return either -# "0001abcd" or "000000000001abcd", depending on the current (global) -# address length. -sub HexExtend { - my $addr = shift; - - $addr =~ s/^(0x)?0*//; - my $zeros_needed = $address_length - length($addr); - if ($zeros_needed < 0) { - printf STDERR "Warning: address $addr is longer than address length $address_length\n"; - return $addr; - } - return ("0" x $zeros_needed) . $addr; -} - -##### Symbol extraction ##### - -# Aggressively search the lib_prefix values for the given library -# If all else fails, just return the name of the library unmodified. -# If the lib_prefix is "/my/path,/other/path" and $file is "/lib/dir/mylib.so" -# it will search the following locations in this order, until it finds a file: -# /my/path/lib/dir/mylib.so -# /other/path/lib/dir/mylib.so -# /my/path/dir/mylib.so -# /other/path/dir/mylib.so -# /my/path/mylib.so -# /other/path/mylib.so -# /lib/dir/mylib.so (returned as last resort) -sub FindLibrary { - my $file = shift; - my $suffix = $file; - - # Search for the library as described above - do { - foreach my $prefix (@prefix_list) { - my $fullpath = $prefix . $suffix; - if (-e $fullpath) { - return $fullpath; - } - } - } while ($suffix =~ s|^/[^/]+/|/|); - return $file; -} - -# Return path to library with debugging symbols. -# For libc libraries, the copy in /usr/lib/debug contains debugging symbols -sub DebuggingLibrary { - my $file = shift; - if ($file =~ m|^/|) { - if (-f "/usr/lib/debug$file") { - return "/usr/lib/debug$file"; - } elsif (-f "/usr/lib/debug$file.debug") { - return "/usr/lib/debug$file.debug"; - } - } - return undef; -} - -# Parse text section header of a library using objdump -sub ParseTextSectionHeaderFromObjdump { - my $lib = shift; - - my $size = undef; - my $vma; - my $file_offset; - # Get objdump output from the library file to figure out how to - # map between mapped addresses and addresses in the library. - my $cmd = ShellEscape($obj_tool_map{"objdump"}, "-h", $lib); - open(OBJDUMP, "$cmd |") || error("$cmd: $!\n"); - while (<OBJDUMP>) { - s/\r//g; # turn windows-looking lines into unix-looking lines - # Idx Name Size VMA LMA File off Algn - # 10 .text 00104b2c 420156f0 420156f0 000156f0 2**4 - # For 64-bit objects, VMA and LMA will be 16 hex digits, size and file - # offset may still be 8. But AddressSub below will still handle that. - my @x = split; - if (($#x >= 6) && ($x[1] eq '.text')) { - $size = $x[2]; - $vma = $x[3]; - $file_offset = $x[5]; - last; - } - } - close(OBJDUMP); - - if (!defined($size)) { - return undef; - } - - my $r = {}; - $r->{size} = $size; - $r->{vma} = $vma; - $r->{file_offset} = $file_offset; - - return $r; -} - -# Parse text section header of a library using otool (on OS X) -sub ParseTextSectionHeaderFromOtool { - my $lib = shift; - - my $size = undef; - my $vma = undef; - my $file_offset = undef; - # Get otool output from the library file to figure out how to - # map between mapped addresses and addresses in the library. - my $command = ShellEscape($obj_tool_map{"otool"}, "-l", $lib); - open(OTOOL, "$command |") || error("$command: $!\n"); - my $cmd = ""; - my $sectname = ""; - my $segname = ""; - foreach my $line (<OTOOL>) { - $line =~ s/\r//g; # turn windows-looking lines into unix-looking lines - # Load command <#> - # cmd LC_SEGMENT - # [...] - # Section - # sectname __text - # segname __TEXT - # addr 0x000009f8 - # size 0x00018b9e - # offset 2552 - # align 2^2 (4) - # We will need to strip off the leading 0x from the hex addresses, - # and convert the offset into hex. - if ($line =~ /Load command/) { - $cmd = ""; - $sectname = ""; - $segname = ""; - } elsif ($line =~ /Section/) { - $sectname = ""; - $segname = ""; - } elsif ($line =~ /cmd (\w+)/) { - $cmd = $1; - } elsif ($line =~ /sectname (\w+)/) { - $sectname = $1; - } elsif ($line =~ /segname (\w+)/) { - $segname = $1; - } elsif (!(($cmd eq "LC_SEGMENT" || $cmd eq "LC_SEGMENT_64") && - $sectname eq "__text" && - $segname eq "__TEXT")) { - next; - } elsif ($line =~ /\baddr 0x([0-9a-fA-F]+)/) { - $vma = $1; - } elsif ($line =~ /\bsize 0x([0-9a-fA-F]+)/) { - $size = $1; - } elsif ($line =~ /\boffset ([0-9]+)/) { - $file_offset = sprintf("%016x", $1); - } - if (defined($vma) && defined($size) && defined($file_offset)) { - last; - } - } - close(OTOOL); - - if (!defined($vma) || !defined($size) || !defined($file_offset)) { - return undef; - } - - my $r = {}; - $r->{size} = $size; - $r->{vma} = $vma; - $r->{file_offset} = $file_offset; - - return $r; -} - -sub ParseTextSectionHeader { - # obj_tool_map("otool") is only defined if we're in a Mach-O environment - if (defined($obj_tool_map{"otool"})) { - my $r = ParseTextSectionHeaderFromOtool(@_); - if (defined($r)){ - return $r; - } - } - # If otool doesn't work, or we don't have it, fall back to objdump - return ParseTextSectionHeaderFromObjdump(@_); -} - -# Split /proc/pid/maps dump into a list of libraries -sub ParseLibraries { - return if $main::use_symbol_page; # We don't need libraries info. - my $prog = Cwd::abs_path(shift); - my $map = shift; - my $pcs = shift; - - my $result = []; - my $h = "[a-f0-9]+"; - my $zero_offset = HexExtend("0"); - - my $buildvar = ""; - foreach my $l (split("\n", $map)) { - if ($l =~ m/^\s*build=(.*)$/) { - $buildvar = $1; - } - - my $start; - my $finish; - my $offset; - my $lib; - if ($l =~ /^($h)-($h)\s+..x.\s+($h)\s+\S+:\S+\s+\d+\s+(\S+\.(so|dll|dylib|bundle)((\.\d+)+\w*(\.\d+){0,3})?)$/i) { - # Full line from /proc/self/maps. Example: - # 40000000-40015000 r-xp 00000000 03:01 12845071 /lib/ld-2.3.2.so - $start = HexExtend($1); - $finish = HexExtend($2); - $offset = HexExtend($3); - $lib = $4; - $lib =~ s|\\|/|g; # turn windows-style paths into unix-style paths - } elsif ($l =~ /^\s*($h)-($h):\s*(\S+\.so(\.\d+)*)/) { - # Cooked line from DumpAddressMap. Example: - # 40000000-40015000: /lib/ld-2.3.2.so - $start = HexExtend($1); - $finish = HexExtend($2); - $offset = $zero_offset; - $lib = $3; - } elsif (($l =~ /^($h)-($h)\s+..x.\s+($h)\s+\S+:\S+\s+\d+\s+(\S+)$/i) && ($4 eq $prog)) { - # PIEs and address space randomization do not play well with our - # default assumption that main executable is at lowest - # addresses. So we're detecting main executable in - # /proc/self/maps as well. - $start = HexExtend($1); - $finish = HexExtend($2); - $offset = HexExtend($3); - $lib = $4; - $lib =~ s|\\|/|g; # turn windows-style paths into unix-style paths - } - # FreeBSD 10.0 virtual memory map /proc/curproc/map as defined in - # function procfs_doprocmap (sys/fs/procfs/procfs_map.c) - # - # Example: - # 0x800600000 0x80061a000 26 0 0xfffff800035a0000 r-x 75 33 0x1004 COW NC vnode /libexec/ld-elf.s - # o.1 NCH -1 - elsif ($l =~ /^(0x$h)\s(0x$h)\s\d+\s\d+\s0x$h\sr-x\s\d+\s\d+\s0x\d+\s(COW|NCO)\s(NC|NNC)\svnode\s(\S+\.so(\.\d+)*)/) { - $start = HexExtend($1); - $finish = HexExtend($2); - $offset = $zero_offset; - $lib = FindLibrary($5); - - } else { - next; - } - - # Expand "$build" variable if available - $lib =~ s/\$build\b/$buildvar/g; - - $lib = FindLibrary($lib); - - # Check for pre-relocated libraries, which use pre-relocated symbol tables - # and thus require adjusting the offset that we'll use to translate - # VM addresses into symbol table addresses. - # Only do this if we're not going to fetch the symbol table from a - # debugging copy of the library. - if (!DebuggingLibrary($lib)) { - my $text = ParseTextSectionHeader($lib); - if (defined($text)) { - my $vma_offset = AddressSub($text->{vma}, $text->{file_offset}); - $offset = AddressAdd($offset, $vma_offset); - } - } - - if($main::opt_debug) { printf STDERR "$start:$finish ($offset) $lib\n"; } - push(@{$result}, [$lib, $start, $finish, $offset]); - } - - # Append special entry for additional library (not relocated) - if ($main::opt_lib ne "") { - my $text = ParseTextSectionHeader($main::opt_lib); - if (defined($text)) { - my $start = $text->{vma}; - my $finish = AddressAdd($start, $text->{size}); - - push(@{$result}, [$main::opt_lib, $start, $finish, $start]); - } - } - - # Append special entry for the main program. This covers - # 0..max_pc_value_seen, so that we assume pc values not found in one - # of the library ranges will be treated as coming from the main - # program binary. - my $min_pc = HexExtend("0"); - my $max_pc = $min_pc; # find the maximal PC value in any sample - foreach my $pc (keys(%{$pcs})) { - if (HexExtend($pc) gt $max_pc) { $max_pc = HexExtend($pc); } - } - push(@{$result}, [$prog, $min_pc, $max_pc, $zero_offset]); - - return $result; -} - -# Add two hex addresses of length $address_length. -# Run jeprof --test for unit test if this is changed. -sub AddressAdd { - my $addr1 = shift; - my $addr2 = shift; - my $sum; - - if ($address_length == 8) { - # Perl doesn't cope with wraparound arithmetic, so do it explicitly: - $sum = (hex($addr1)+hex($addr2)) % (0x10000000 * 16); - return sprintf("%08x", $sum); - - } else { - # Do the addition in 7-nibble chunks to trivialize carry handling. - - if ($main::opt_debug and $main::opt_test) { - print STDERR "AddressAdd $addr1 + $addr2 = "; - } - - my $a1 = substr($addr1,-7); - $addr1 = substr($addr1,0,-7); - my $a2 = substr($addr2,-7); - $addr2 = substr($addr2,0,-7); - $sum = hex($a1) + hex($a2); - my $c = 0; - if ($sum > 0xfffffff) { - $c = 1; - $sum -= 0x10000000; - } - my $r = sprintf("%07x", $sum); - - $a1 = substr($addr1,-7); - $addr1 = substr($addr1,0,-7); - $a2 = substr($addr2,-7); - $addr2 = substr($addr2,0,-7); - $sum = hex($a1) + hex($a2) + $c; - $c = 0; - if ($sum > 0xfffffff) { - $c = 1; - $sum -= 0x10000000; - } - $r = sprintf("%07x", $sum) . $r; - - $sum = hex($addr1) + hex($addr2) + $c; - if ($sum > 0xff) { $sum -= 0x100; } - $r = sprintf("%02x", $sum) . $r; - - if ($main::opt_debug and $main::opt_test) { print STDERR "$r\n"; } - - return $r; - } -} - - -# Subtract two hex addresses of length $address_length. -# Run jeprof --test for unit test if this is changed. -sub AddressSub { - my $addr1 = shift; - my $addr2 = shift; - my $diff; - - if ($address_length == 8) { - # Perl doesn't cope with wraparound arithmetic, so do it explicitly: - $diff = (hex($addr1)-hex($addr2)) % (0x10000000 * 16); - return sprintf("%08x", $diff); - - } else { - # Do the addition in 7-nibble chunks to trivialize borrow handling. - # if ($main::opt_debug) { print STDERR "AddressSub $addr1 - $addr2 = "; } - - my $a1 = hex(substr($addr1,-7)); - $addr1 = substr($addr1,0,-7); - my $a2 = hex(substr($addr2,-7)); - $addr2 = substr($addr2,0,-7); - my $b = 0; - if ($a2 > $a1) { - $b = 1; - $a1 += 0x10000000; - } - $diff = $a1 - $a2; - my $r = sprintf("%07x", $diff); - - $a1 = hex(substr($addr1,-7)); - $addr1 = substr($addr1,0,-7); - $a2 = hex(substr($addr2,-7)) + $b; - $addr2 = substr($addr2,0,-7); - $b = 0; - if ($a2 > $a1) { - $b = 1; - $a1 += 0x10000000; - } - $diff = $a1 - $a2; - $r = sprintf("%07x", $diff) . $r; - - $a1 = hex($addr1); - $a2 = hex($addr2) + $b; - if ($a2 > $a1) { $a1 += 0x100; } - $diff = $a1 - $a2; - $r = sprintf("%02x", $diff) . $r; - - # if ($main::opt_debug) { print STDERR "$r\n"; } - - return $r; - } -} - -# Increment a hex addresses of length $address_length. -# Run jeprof --test for unit test if this is changed. -sub AddressInc { - my $addr = shift; - my $sum; - - if ($address_length == 8) { - # Perl doesn't cope with wraparound arithmetic, so do it explicitly: - $sum = (hex($addr)+1) % (0x10000000 * 16); - return sprintf("%08x", $sum); - - } else { - # Do the addition in 7-nibble chunks to trivialize carry handling. - # We are always doing this to step through the addresses in a function, - # and will almost never overflow the first chunk, so we check for this - # case and exit early. - - # if ($main::opt_debug) { print STDERR "AddressInc $addr1 = "; } - - my $a1 = substr($addr,-7); - $addr = substr($addr,0,-7); - $sum = hex($a1) + 1; - my $r = sprintf("%07x", $sum); - if ($sum <= 0xfffffff) { - $r = $addr . $r; - # if ($main::opt_debug) { print STDERR "$r\n"; } - return HexExtend($r); - } else { - $r = "0000000"; - } - - $a1 = substr($addr,-7); - $addr = substr($addr,0,-7); - $sum = hex($a1) + 1; - $r = sprintf("%07x", $sum) . $r; - if ($sum <= 0xfffffff) { - $r = $addr . $r; - # if ($main::opt_debug) { print STDERR "$r\n"; } - return HexExtend($r); - } else { - $r = "00000000000000"; - } - - $sum = hex($addr) + 1; - if ($sum > 0xff) { $sum -= 0x100; } - $r = sprintf("%02x", $sum) . $r; - - # if ($main::opt_debug) { print STDERR "$r\n"; } - return $r; - } -} - -# Extract symbols for all PC values found in profile -sub ExtractSymbols { - my $libs = shift; - my $pcset = shift; - - my $symbols = {}; - - # Map each PC value to the containing library. To make this faster, - # we sort libraries by their starting pc value (highest first), and - # advance through the libraries as we advance the pc. Sometimes the - # addresses of libraries may overlap with the addresses of the main - # binary, so to make sure the libraries 'win', we iterate over the - # libraries in reverse order (which assumes the binary doesn't start - # in the middle of a library, which seems a fair assumption). - my @pcs = (sort { $a cmp $b } keys(%{$pcset})); # pcset is 0-extended strings - foreach my $lib (sort {$b->[1] cmp $a->[1]} @{$libs}) { - my $libname = $lib->[0]; - my $start = $lib->[1]; - my $finish = $lib->[2]; - my $offset = $lib->[3]; - - # Use debug library if it exists - my $debug_libname = DebuggingLibrary($libname); - if ($debug_libname) { - $libname = $debug_libname; - } - - # Get list of pcs that belong in this library. - my $contained = []; - my ($start_pc_index, $finish_pc_index); - # Find smallest finish_pc_index such that $finish < $pc[$finish_pc_index]. - for ($finish_pc_index = $#pcs + 1; $finish_pc_index > 0; - $finish_pc_index--) { - last if $pcs[$finish_pc_index - 1] le $finish; - } - # Find smallest start_pc_index such that $start <= $pc[$start_pc_index]. - for ($start_pc_index = $finish_pc_index; $start_pc_index > 0; - $start_pc_index--) { - last if $pcs[$start_pc_index - 1] lt $start; - } - # This keeps PC values higher than $pc[$finish_pc_index] in @pcs, - # in case there are overlaps in libraries and the main binary. - @{$contained} = splice(@pcs, $start_pc_index, - $finish_pc_index - $start_pc_index); - # Map to symbols - MapToSymbols($libname, AddressSub($start, $offset), $contained, $symbols); - } - - return $symbols; -} - -# Map list of PC values to symbols for a given image -sub MapToSymbols { - my $image = shift; - my $offset = shift; - my $pclist = shift; - my $symbols = shift; - - my $debug = 0; - - # Ignore empty binaries - if ($#{$pclist} < 0) { return; } - - # Figure out the addr2line command to use - my $addr2line = $obj_tool_map{"addr2line"}; - my $cmd = ShellEscape($addr2line, "-f", "-C", "-e", $image); - if (exists $obj_tool_map{"addr2line_pdb"}) { - $addr2line = $obj_tool_map{"addr2line_pdb"}; - $cmd = ShellEscape($addr2line, "--demangle", "-f", "-C", "-e", $image); - } - - # If "addr2line" isn't installed on the system at all, just use - # nm to get what info we can (function names, but not line numbers). - if (system(ShellEscape($addr2line, "--help") . " >$dev_null 2>&1") != 0) { - MapSymbolsWithNM($image, $offset, $pclist, $symbols); - return; - } - - # "addr2line -i" can produce a variable number of lines per input - # address, with no separator that allows us to tell when data for - # the next address starts. So we find the address for a special - # symbol (_fini) and interleave this address between all real - # addresses passed to addr2line. The name of this special symbol - # can then be used as a separator. - $sep_address = undef; # May be filled in by MapSymbolsWithNM() - my $nm_symbols = {}; - MapSymbolsWithNM($image, $offset, $pclist, $nm_symbols); - if (defined($sep_address)) { - # Only add " -i" to addr2line if the binary supports it. - # addr2line --help returns 0, but not if it sees an unknown flag first. - if (system("$cmd -i --help >$dev_null 2>&1") == 0) { - $cmd .= " -i"; - } else { - $sep_address = undef; # no need for sep_address if we don't support -i - } - } - - # Make file with all PC values with intervening 'sep_address' so - # that we can reliably detect the end of inlined function list - open(ADDRESSES, ">$main::tmpfile_sym") || error("$main::tmpfile_sym: $!\n"); - if ($debug) { print("---- $image ---\n"); } - for (my $i = 0; $i <= $#{$pclist}; $i++) { - # addr2line always reads hex addresses, and does not need '0x' prefix. - if ($debug) { printf STDERR ("%s\n", $pclist->[$i]); } - printf ADDRESSES ("%s\n", AddressSub($pclist->[$i], $offset)); - if (defined($sep_address)) { - printf ADDRESSES ("%s\n", $sep_address); - } - } - close(ADDRESSES); - if ($debug) { - print("----\n"); - system("cat", $main::tmpfile_sym); - print("----\n"); - system("$cmd < " . ShellEscape($main::tmpfile_sym)); - print("----\n"); - } - - open(SYMBOLS, "$cmd <" . ShellEscape($main::tmpfile_sym) . " |") - || error("$cmd: $!\n"); - my $count = 0; # Index in pclist - while (<SYMBOLS>) { - # Read fullfunction and filelineinfo from next pair of lines - s/\r?\n$//g; - my $fullfunction = $_; - $_ = <SYMBOLS>; - s/\r?\n$//g; - my $filelinenum = $_; - - if (defined($sep_address) && $fullfunction eq $sep_symbol) { - # Terminating marker for data for this address - $count++; - next; - } - - $filelinenum =~ s|\\|/|g; # turn windows-style paths into unix-style paths - - my $pcstr = $pclist->[$count]; - my $function = ShortFunctionName($fullfunction); - my $nms = $nm_symbols->{$pcstr}; - if (defined($nms)) { - if ($fullfunction eq '??') { - # nm found a symbol for us. - $function = $nms->[0]; - $fullfunction = $nms->[2]; - } else { - # MapSymbolsWithNM tags each routine with its starting address, - # useful in case the image has multiple occurrences of this - # routine. (It uses a syntax that resembles template paramters, - # that are automatically stripped out by ShortFunctionName().) - # addr2line does not provide the same information. So we check - # if nm disambiguated our symbol, and if so take the annotated - # (nm) version of the routine-name. TODO(csilvers): this won't - # catch overloaded, inlined symbols, which nm doesn't see. - # Better would be to do a check similar to nm's, in this fn. - if ($nms->[2] =~ m/^\Q$function\E/) { # sanity check it's the right fn - $function = $nms->[0]; - $fullfunction = $nms->[2]; - } - } - } - - # Prepend to accumulated symbols for pcstr - # (so that caller comes before callee) - my $sym = $symbols->{$pcstr}; - if (!defined($sym)) { - $sym = []; - $symbols->{$pcstr} = $sym; - } - unshift(@{$sym}, $function, $filelinenum, $fullfunction); - if ($debug) { printf STDERR ("%s => [%s]\n", $pcstr, join(" ", @{$sym})); } - if (!defined($sep_address)) { - # Inlining is off, so this entry ends immediately - $count++; - } - } - close(SYMBOLS); -} - -# Use nm to map the list of referenced PCs to symbols. Return true iff we -# are able to read procedure information via nm. -sub MapSymbolsWithNM { - my $image = shift; - my $offset = shift; - my $pclist = shift; - my $symbols = shift; - - # Get nm output sorted by increasing address - my $symbol_table = GetProcedureBoundaries($image, "."); - if (!%{$symbol_table}) { - return 0; - } - # Start addresses are already the right length (8 or 16 hex digits). - my @names = sort { $symbol_table->{$a}->[0] cmp $symbol_table->{$b}->[0] } - keys(%{$symbol_table}); - - if ($#names < 0) { - # No symbols: just use addresses - foreach my $pc (@{$pclist}) { - my $pcstr = "0x" . $pc; - $symbols->{$pc} = [$pcstr, "?", $pcstr]; - } - return 0; - } - - # Sort addresses so we can do a join against nm output - my $index = 0; - my $fullname = $names[0]; - my $name = ShortFunctionName($fullname); - foreach my $pc (sort { $a cmp $b } @{$pclist}) { - # Adjust for mapped offset - my $mpc = AddressSub($pc, $offset); - while (($index < $#names) && ($mpc ge $symbol_table->{$fullname}->[1])){ - $index++; - $fullname = $names[$index]; - $name = ShortFunctionName($fullname); - } - if ($mpc lt $symbol_table->{$fullname}->[1]) { - $symbols->{$pc} = [$name, "?", $fullname]; - } else { - my $pcstr = "0x" . $pc; - $symbols->{$pc} = [$pcstr, "?", $pcstr]; - } - } - return 1; -} - -sub ShortFunctionName { - my $function = shift; - while ($function =~ s/\([^()]*\)(\s*const)?//g) { } # Argument types - while ($function =~ s/<[^<>]*>//g) { } # Remove template arguments - $function =~ s/^.*\s+(\w+::)/$1/; # Remove leading type - return $function; -} - -# Trim overly long symbols found in disassembler output -sub CleanDisassembly { - my $d = shift; - while ($d =~ s/\([^()%]*\)(\s*const)?//g) { } # Argument types, not (%rax) - while ($d =~ s/(\w+)<[^<>]*>/$1/g) { } # Remove template arguments - return $d; -} - -# Clean file name for display -sub CleanFileName { - my ($f) = @_; - $f =~ s|^/proc/self/cwd/||; - $f =~ s|^\./||; - return $f; -} - -# Make address relative to section and clean up for display -sub UnparseAddress { - my ($offset, $address) = @_; - $address = AddressSub($address, $offset); - $address =~ s/^0x//; - $address =~ s/^0*//; - return $address; -} - -##### Miscellaneous ##### - -# Find the right versions of the above object tools to use. The -# argument is the program file being analyzed, and should be an ELF -# 32-bit or ELF 64-bit executable file. The location of the tools -# is determined by considering the following options in this order: -# 1) --tools option, if set -# 2) JEPROF_TOOLS environment variable, if set -# 3) the environment -sub ConfigureObjTools { - my $prog_file = shift; - - # Check for the existence of $prog_file because /usr/bin/file does not - # predictably return error status in prod. - (-e $prog_file) || error("$prog_file does not exist.\n"); - - my $file_type = undef; - if (-e "/usr/bin/file") { - # Follow symlinks (at least for systems where "file" supports that). - my $escaped_prog_file = ShellEscape($prog_file); - $file_type = `/usr/bin/file -L $escaped_prog_file 2>$dev_null || - /usr/bin/file $escaped_prog_file`; - } elsif ($^O == "MSWin32") { - $file_type = "MS Windows"; - } else { - print STDERR "WARNING: Can't determine the file type of $prog_file"; - } - - if ($file_type =~ /64-bit/) { - # Change $address_length to 16 if the program file is ELF 64-bit. - # We can't detect this from many (most?) heap or lock contention - # profiles, since the actual addresses referenced are generally in low - # memory even for 64-bit programs. - $address_length = 16; - } - - if ($file_type =~ /MS Windows/) { - # For windows, we provide a version of nm and addr2line as part of - # the opensource release, which is capable of parsing - # Windows-style PDB executables. It should live in the path, or - # in the same directory as jeprof. - $obj_tool_map{"nm_pdb"} = "nm-pdb"; - $obj_tool_map{"addr2line_pdb"} = "addr2line-pdb"; - } - - if ($file_type =~ /Mach-O/) { - # OS X uses otool to examine Mach-O files, rather than objdump. - $obj_tool_map{"otool"} = "otool"; - $obj_tool_map{"addr2line"} = "false"; # no addr2line - $obj_tool_map{"objdump"} = "false"; # no objdump - } - - # Go fill in %obj_tool_map with the pathnames to use: - foreach my $tool (keys %obj_tool_map) { - $obj_tool_map{$tool} = ConfigureTool($obj_tool_map{$tool}); - } -} - -# Returns the path of a caller-specified object tool. If --tools or -# JEPROF_TOOLS are specified, then returns the full path to the tool -# with that prefix. Otherwise, returns the path unmodified (which -# means we will look for it on PATH). -sub ConfigureTool { - my $tool = shift; - my $path; - - # --tools (or $JEPROF_TOOLS) is a comma separated list, where each - # item is either a) a pathname prefix, or b) a map of the form - # <tool>:<path>. First we look for an entry of type (b) for our - # tool. If one is found, we use it. Otherwise, we consider all the - # pathname prefixes in turn, until one yields an existing file. If - # none does, we use a default path. - my $tools = $main::opt_tools || $ENV{"JEPROF_TOOLS"} || ""; - if ($tools =~ m/(,|^)\Q$tool\E:([^,]*)/) { - $path = $2; - # TODO(csilvers): sanity-check that $path exists? Hard if it's relative. - } elsif ($tools ne '') { - foreach my $prefix (split(',', $tools)) { - next if ($prefix =~ /:/); # ignore "tool:fullpath" entries in the list - if (-x $prefix . $tool) { - $path = $prefix . $tool; - last; - } - } - if (!$path) { - error("No '$tool' found with prefix specified by " . - "--tools (or \$JEPROF_TOOLS) '$tools'\n"); - } - } else { - # ... otherwise use the version that exists in the same directory as - # jeprof. If there's nothing there, use $PATH. - $0 =~ m,[^/]*$,; # this is everything after the last slash - my $dirname = $`; # this is everything up to and including the last slash - if (-x "$dirname$tool") { - $path = "$dirname$tool"; - } else { - $path = $tool; - } - } - if ($main::opt_debug) { print STDERR "Using '$path' for '$tool'.\n"; } - return $path; -} - -sub ShellEscape { - my @escaped_words = (); - foreach my $word (@_) { - my $escaped_word = $word; - if ($word =~ m![^a-zA-Z0-9/.,_=-]!) { # check for anything not in whitelist - $escaped_word =~ s/'/'\\''/; - $escaped_word = "'$escaped_word'"; - } - push(@escaped_words, $escaped_word); - } - return join(" ", @escaped_words); -} - -sub cleanup { - unlink($main::tmpfile_sym); - unlink(keys %main::tempnames); - - # We leave any collected profiles in $HOME/jeprof in case the user wants - # to look at them later. We print a message informing them of this. - if ((scalar(@main::profile_files) > 0) && - defined($main::collected_profile)) { - if (scalar(@main::profile_files) == 1) { - print STDERR "Dynamically gathered profile is in $main::collected_profile\n"; - } - print STDERR "If you want to investigate this profile further, you can do:\n"; - print STDERR "\n"; - print STDERR " jeprof \\\n"; - print STDERR " $main::prog \\\n"; - print STDERR " $main::collected_profile\n"; - print STDERR "\n"; - } -} - -sub sighandler { - cleanup(); - exit(1); -} - -sub error { - my $msg = shift; - print STDERR $msg; - cleanup(); - exit(1); -} - - -# Run $nm_command and get all the resulting procedure boundaries whose -# names match "$regexp" and returns them in a hashtable mapping from -# procedure name to a two-element vector of [start address, end address] -sub GetProcedureBoundariesViaNm { - my $escaped_nm_command = shift; # shell-escaped - my $regexp = shift; - - my $symbol_table = {}; - open(NM, "$escaped_nm_command |") || error("$escaped_nm_command: $!\n"); - my $last_start = "0"; - my $routine = ""; - while (<NM>) { - s/\r//g; # turn windows-looking lines into unix-looking lines - if (m/^\s*([0-9a-f]+) (.) (..*)/) { - my $start_val = $1; - my $type = $2; - my $this_routine = $3; - - # It's possible for two symbols to share the same address, if - # one is a zero-length variable (like __start_google_malloc) or - # one symbol is a weak alias to another (like __libc_malloc). - # In such cases, we want to ignore all values except for the - # actual symbol, which in nm-speak has type "T". The logic - # below does this, though it's a bit tricky: what happens when - # we have a series of lines with the same address, is the first - # one gets queued up to be processed. However, it won't - # *actually* be processed until later, when we read a line with - # a different address. That means that as long as we're reading - # lines with the same address, we have a chance to replace that - # item in the queue, which we do whenever we see a 'T' entry -- - # that is, a line with type 'T'. If we never see a 'T' entry, - # we'll just go ahead and process the first entry (which never - # got touched in the queue), and ignore the others. - if ($start_val eq $last_start && $type =~ /t/i) { - # We are the 'T' symbol at this address, replace previous symbol. - $routine = $this_routine; - next; - } elsif ($start_val eq $last_start) { - # We're not the 'T' symbol at this address, so ignore us. - next; - } - - if ($this_routine eq $sep_symbol) { - $sep_address = HexExtend($start_val); - } - - # Tag this routine with the starting address in case the image - # has multiple occurrences of this routine. We use a syntax - # that resembles template parameters that are automatically - # stripped out by ShortFunctionName() - $this_routine .= "<$start_val>"; - - if (defined($routine) && $routine =~ m/$regexp/) { - $symbol_table->{$routine} = [HexExtend($last_start), - HexExtend($start_val)]; - } - $last_start = $start_val; - $routine = $this_routine; - } elsif (m/^Loaded image name: (.+)/) { - # The win32 nm workalike emits information about the binary it is using. - if ($main::opt_debug) { print STDERR "Using Image $1\n"; } - } elsif (m/^PDB file name: (.+)/) { - # The win32 nm workalike emits information about the pdb it is using. - if ($main::opt_debug) { print STDERR "Using PDB $1\n"; } - } - } - close(NM); - # Handle the last line in the nm output. Unfortunately, we don't know - # how big this last symbol is, because we don't know how big the file - # is. For now, we just give it a size of 0. - # TODO(csilvers): do better here. - if (defined($routine) && $routine =~ m/$regexp/) { - $symbol_table->{$routine} = [HexExtend($last_start), - HexExtend($last_start)]; - } - return $symbol_table; -} - -# Gets the procedure boundaries for all routines in "$image" whose names -# match "$regexp" and returns them in a hashtable mapping from procedure -# name to a two-element vector of [start address, end address]. -# Will return an empty map if nm is not installed or not working properly. -sub GetProcedureBoundaries { - my $image = shift; - my $regexp = shift; - - # If $image doesn't start with /, then put ./ in front of it. This works - # around an obnoxious bug in our probing of nm -f behavior. - # "nm -f $image" is supposed to fail on GNU nm, but if: - # - # a. $image starts with [BbSsPp] (for example, bin/foo/bar), AND - # b. you have a.out in your current directory (a not uncommon occurence) - # - # then "nm -f $image" succeeds because -f only looks at the first letter of - # the argument, which looks valid because it's [BbSsPp], and then since - # there's no image provided, it looks for a.out and finds it. - # - # This regex makes sure that $image starts with . or /, forcing the -f - # parsing to fail since . and / are not valid formats. - $image =~ s#^[^/]#./$&#; - - # For libc libraries, the copy in /usr/lib/debug contains debugging symbols - my $debugging = DebuggingLibrary($image); - if ($debugging) { - $image = $debugging; - } - - my $nm = $obj_tool_map{"nm"}; - my $cppfilt = $obj_tool_map{"c++filt"}; - - # nm can fail for two reasons: 1) $image isn't a debug library; 2) nm - # binary doesn't support --demangle. In addition, for OS X we need - # to use the -f flag to get 'flat' nm output (otherwise we don't sort - # properly and get incorrect results). Unfortunately, GNU nm uses -f - # in an incompatible way. So first we test whether our nm supports - # --demangle and -f. - my $demangle_flag = ""; - my $cppfilt_flag = ""; - my $to_devnull = ">$dev_null 2>&1"; - if (system(ShellEscape($nm, "--demangle", $image) . $to_devnull) == 0) { - # In this mode, we do "nm --demangle <foo>" - $demangle_flag = "--demangle"; - $cppfilt_flag = ""; - } elsif (system(ShellEscape($cppfilt, $image) . $to_devnull) == 0) { - # In this mode, we do "nm <foo> | c++filt" - $cppfilt_flag = " | " . ShellEscape($cppfilt); - }; - my $flatten_flag = ""; - if (system(ShellEscape($nm, "-f", $image) . $to_devnull) == 0) { - $flatten_flag = "-f"; - } - - # Finally, in the case $imagie isn't a debug library, we try again with - # -D to at least get *exported* symbols. If we can't use --demangle, - # we use c++filt instead, if it exists on this system. - my @nm_commands = (ShellEscape($nm, "-n", $flatten_flag, $demangle_flag, - $image) . " 2>$dev_null $cppfilt_flag", - ShellEscape($nm, "-D", "-n", $flatten_flag, $demangle_flag, - $image) . " 2>$dev_null $cppfilt_flag", - # 6nm is for Go binaries - ShellEscape("6nm", "$image") . " 2>$dev_null | sort", - ); - - # If the executable is an MS Windows PDB-format executable, we'll - # have set up obj_tool_map("nm_pdb"). In this case, we actually - # want to use both unix nm and windows-specific nm_pdb, since - # PDB-format executables can apparently include dwarf .o files. - if (exists $obj_tool_map{"nm_pdb"}) { - push(@nm_commands, - ShellEscape($obj_tool_map{"nm_pdb"}, "--demangle", $image) - . " 2>$dev_null"); - } - - foreach my $nm_command (@nm_commands) { - my $symbol_table = GetProcedureBoundariesViaNm($nm_command, $regexp); - return $symbol_table if (%{$symbol_table}); - } - my $symbol_table = {}; - return $symbol_table; -} - - -# The test vectors for AddressAdd/Sub/Inc are 8-16-nibble hex strings. -# To make them more readable, we add underscores at interesting places. -# This routine removes the underscores, producing the canonical representation -# used by jeprof to represent addresses, particularly in the tested routines. -sub CanonicalHex { - my $arg = shift; - return join '', (split '_',$arg); -} - - -# Unit test for AddressAdd: -sub AddressAddUnitTest { - my $test_data_8 = shift; - my $test_data_16 = shift; - my $error_count = 0; - my $fail_count = 0; - my $pass_count = 0; - # print STDERR "AddressAddUnitTest: ", 1+$#{$test_data_8}, " tests\n"; - - # First a few 8-nibble addresses. Note that this implementation uses - # plain old arithmetic, so a quick sanity check along with verifying what - # happens to overflow (we want it to wrap): - $address_length = 8; - foreach my $row (@{$test_data_8}) { - if ($main::opt_debug and $main::opt_test) { print STDERR "@{$row}\n"; } - my $sum = AddressAdd ($row->[0], $row->[1]); - if ($sum ne $row->[2]) { - printf STDERR "ERROR: %s != %s + %s = %s\n", $sum, - $row->[0], $row->[1], $row->[2]; - ++$fail_count; - } else { - ++$pass_count; - } - } - printf STDERR "AddressAdd 32-bit tests: %d passes, %d failures\n", - $pass_count, $fail_count; - $error_count = $fail_count; - $fail_count = 0; - $pass_count = 0; - - # Now 16-nibble addresses. - $address_length = 16; - foreach my $row (@{$test_data_16}) { - if ($main::opt_debug and $main::opt_test) { print STDERR "@{$row}\n"; } - my $sum = AddressAdd (CanonicalHex($row->[0]), CanonicalHex($row->[1])); - my $expected = join '', (split '_',$row->[2]); - if ($sum ne CanonicalHex($row->[2])) { - printf STDERR "ERROR: %s != %s + %s = %s\n", $sum, - $row->[0], $row->[1], $row->[2]; - ++$fail_count; - } else { - ++$pass_count; - } - } - printf STDERR "AddressAdd 64-bit tests: %d passes, %d failures\n", - $pass_count, $fail_count; - $error_count += $fail_count; - - return $error_count; -} - - -# Unit test for AddressSub: -sub AddressSubUnitTest { - my $test_data_8 = shift; - my $test_data_16 = shift; - my $error_count = 0; - my $fail_count = 0; - my $pass_count = 0; - # print STDERR "AddressSubUnitTest: ", 1+$#{$test_data_8}, " tests\n"; - - # First a few 8-nibble addresses. Note that this implementation uses - # plain old arithmetic, so a quick sanity check along with verifying what - # happens to overflow (we want it to wrap): - $address_length = 8; - foreach my $row (@{$test_data_8}) { - if ($main::opt_debug and $main::opt_test) { print STDERR "@{$row}\n"; } - my $sum = AddressSub ($row->[0], $row->[1]); - if ($sum ne $row->[3]) { - printf STDERR "ERROR: %s != %s - %s = %s\n", $sum, - $row->[0], $row->[1], $row->[3]; - ++$fail_count; - } else { - ++$pass_count; - } - } - printf STDERR "AddressSub 32-bit tests: %d passes, %d failures\n", - $pass_count, $fail_count; - $error_count = $fail_count; - $fail_count = 0; - $pass_count = 0; - - # Now 16-nibble addresses. - $address_length = 16; - foreach my $row (@{$test_data_16}) { - if ($main::opt_debug and $main::opt_test) { print STDERR "@{$row}\n"; } - my $sum = AddressSub (CanonicalHex($row->[0]), CanonicalHex($row->[1])); - if ($sum ne CanonicalHex($row->[3])) { - printf STDERR "ERROR: %s != %s - %s = %s\n", $sum, - $row->[0], $row->[1], $row->[3]; - ++$fail_count; - } else { - ++$pass_count; - } - } - printf STDERR "AddressSub 64-bit tests: %d passes, %d failures\n", - $pass_count, $fail_count; - $error_count += $fail_count; - - return $error_count; -} - - -# Unit test for AddressInc: -sub AddressIncUnitTest { - my $test_data_8 = shift; - my $test_data_16 = shift; - my $error_count = 0; - my $fail_count = 0; - my $pass_count = 0; - # print STDERR "AddressIncUnitTest: ", 1+$#{$test_data_8}, " tests\n"; - - # First a few 8-nibble addresses. Note that this implementation uses - # plain old arithmetic, so a quick sanity check along with verifying what - # happens to overflow (we want it to wrap): - $address_length = 8; - foreach my $row (@{$test_data_8}) { - if ($main::opt_debug and $main::opt_test) { print STDERR "@{$row}\n"; } - my $sum = AddressInc ($row->[0]); - if ($sum ne $row->[4]) { - printf STDERR "ERROR: %s != %s + 1 = %s\n", $sum, - $row->[0], $row->[4]; - ++$fail_count; - } else { - ++$pass_count; - } - } - printf STDERR "AddressInc 32-bit tests: %d passes, %d failures\n", - $pass_count, $fail_count; - $error_count = $fail_count; - $fail_count = 0; - $pass_count = 0; - - # Now 16-nibble addresses. - $address_length = 16; - foreach my $row (@{$test_data_16}) { - if ($main::opt_debug and $main::opt_test) { print STDERR "@{$row}\n"; } - my $sum = AddressInc (CanonicalHex($row->[0])); - if ($sum ne CanonicalHex($row->[4])) { - printf STDERR "ERROR: %s != %s + 1 = %s\n", $sum, - $row->[0], $row->[4]; - ++$fail_count; - } else { - ++$pass_count; - } - } - printf STDERR "AddressInc 64-bit tests: %d passes, %d failures\n", - $pass_count, $fail_count; - $error_count += $fail_count; - - return $error_count; -} - - -# Driver for unit tests. -# Currently just the address add/subtract/increment routines for 64-bit. -sub RunUnitTests { - my $error_count = 0; - - # This is a list of tuples [a, b, a+b, a-b, a+1] - my $unit_test_data_8 = [ - [qw(aaaaaaaa 50505050 fafafafa 5a5a5a5a aaaaaaab)], - [qw(50505050 aaaaaaaa fafafafa a5a5a5a6 50505051)], - [qw(ffffffff aaaaaaaa aaaaaaa9 55555555 00000000)], - [qw(00000001 ffffffff 00000000 00000002 00000002)], - [qw(00000001 fffffff0 fffffff1 00000011 00000002)], - ]; - my $unit_test_data_16 = [ - # The implementation handles data in 7-nibble chunks, so those are the - # interesting boundaries. - [qw(aaaaaaaa 50505050 - 00_000000f_afafafa 00_0000005_a5a5a5a 00_000000a_aaaaaab)], - [qw(50505050 aaaaaaaa - 00_000000f_afafafa ff_ffffffa_5a5a5a6 00_0000005_0505051)], - [qw(ffffffff aaaaaaaa - 00_000001a_aaaaaa9 00_0000005_5555555 00_0000010_0000000)], - [qw(00000001 ffffffff - 00_0000010_0000000 ff_ffffff0_0000002 00_0000000_0000002)], - [qw(00000001 fffffff0 - 00_000000f_ffffff1 ff_ffffff0_0000011 00_0000000_0000002)], - - [qw(00_a00000a_aaaaaaa 50505050 - 00_a00000f_afafafa 00_a000005_a5a5a5a 00_a00000a_aaaaaab)], - [qw(0f_fff0005_0505050 aaaaaaaa - 0f_fff000f_afafafa 0f_ffefffa_5a5a5a6 0f_fff0005_0505051)], - [qw(00_000000f_fffffff 01_800000a_aaaaaaa - 01_800001a_aaaaaa9 fe_8000005_5555555 00_0000010_0000000)], - [qw(00_0000000_0000001 ff_fffffff_fffffff - 00_0000000_0000000 00_0000000_0000002 00_0000000_0000002)], - [qw(00_0000000_0000001 ff_fffffff_ffffff0 - ff_fffffff_ffffff1 00_0000000_0000011 00_0000000_0000002)], - ]; - - $error_count += AddressAddUnitTest($unit_test_data_8, $unit_test_data_16); - $error_count += AddressSubUnitTest($unit_test_data_8, $unit_test_data_16); - $error_count += AddressIncUnitTest($unit_test_data_8, $unit_test_data_16); - if ($error_count > 0) { - print STDERR $error_count, " errors: FAILED\n"; - } else { - print STDERR "PASS\n"; - } - exit ($error_count); -} ->>>>>>> main diff --git a/contrib/jemalloc/build-aux/config.guess b/contrib/jemalloc/build-aux/config.guess index e8241c60f184..f7727026b706 100755 --- a/contrib/jemalloc/build-aux/config.guess +++ b/contrib/jemalloc/build-aux/config.guess @@ -1,4 +1,3 @@ -<<<<<<< HEAD #! /bin/sh # Attempt to guess a canonical system name. # Copyright 1992-2021 Free Software Foundation, Inc. @@ -1700,1468 +1699,3 @@ exit 1 # time-stamp-format: "%:y-%02m-%02d" # time-stamp-end: "'" # End: -||||||| dec341af7695 -======= -#! /bin/sh -# Attempt to guess a canonical system name. -# Copyright 1992-2016 Free Software Foundation, Inc. - -timestamp='2016-10-02' - -# 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 -# the Free Software Foundation; either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, see <http://www.gnu.org/licenses/>. -# -# As a special exception to the GNU General Public License, if you -# distribute this file as part of a program that contains a -# configuration script generated by Autoconf, you may include it under -# the same distribution terms that you use for the rest of that -# program. This Exception is an additional permission under section 7 -# of the GNU General Public License, version 3 ("GPLv3"). -# -# Originally written by Per Bothner; maintained since 2000 by Ben Elliston. -# -# 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 -# -# Please send patches to <config-patches@gnu.org>. - - -me=`echo "$0" | sed -e 's,.*/,,'` - -usage="\ -Usage: $0 [OPTION] - -Output the configuration name of the system \`$me' is run on. - -Operation modes: - -h, --help print this help, then exit - -t, --time-stamp print date of last modification, then exit - -v, --version print version number, then exit - -Report bugs and patches to <config-patches@gnu.org>." - -version="\ -GNU config.guess ($timestamp) - -Originally written by Per Bothner. -Copyright 1992-2016 Free Software Foundation, Inc. - -This is free software; see the source for copying conditions. There is NO -warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." - -help=" -Try \`$me --help' for more information." - -# Parse command line -while test $# -gt 0 ; do - case $1 in - --time-stamp | --time* | -t ) - echo "$timestamp" ; exit ;; - --version | -v ) - echo "$version" ; exit ;; - --help | --h* | -h ) - echo "$usage"; exit ;; - -- ) # Stop option processing - shift; break ;; - - ) # Use stdin as input. - break ;; - -* ) - echo "$me: invalid option $1$help" >&2 - exit 1 ;; - * ) - break ;; - esac -done - -if test $# != 0; then - echo "$me: too many arguments$help" >&2 - exit 1 -fi - -trap 'exit 1' 1 2 15 - -# CC_FOR_BUILD -- compiler used by this script. Note that the use of a -# compiler to aid in system detection is discouraged as it requires -# temporary files to be created and, as you can see below, it is a -# headache to deal with in a portable fashion. - -# Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still -# use `HOST_CC' if defined, but it is deprecated. - -# Portable tmp directory creation inspired by the Autoconf team. - -set_cc_for_build=' -trap "exitcode=\$?; (rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null) && exit \$exitcode" 0 ; -trap "rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null; exit 1" 1 2 13 15 ; -: ${TMPDIR=/tmp} ; - { tmp=`(umask 077 && mktemp -d "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } || - { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir $tmp) ; } || - { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir $tmp) && echo "Warning: creating insecure temp directory" >&2 ; } || - { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } ; -dummy=$tmp/dummy ; -tmpfiles="$dummy.c $dummy.o $dummy.rel $dummy" ; -case $CC_FOR_BUILD,$HOST_CC,$CC in - ,,) echo "int x;" > $dummy.c ; - for c in cc gcc c89 c99 ; do - if ($c -c -o $dummy.o $dummy.c) >/dev/null 2>&1 ; then - CC_FOR_BUILD="$c"; break ; - fi ; - done ; - if test x"$CC_FOR_BUILD" = x ; then - CC_FOR_BUILD=no_compiler_found ; - fi - ;; - ,,*) CC_FOR_BUILD=$CC ;; - ,*,*) CC_FOR_BUILD=$HOST_CC ;; -esac ; set_cc_for_build= ;' - -# This is needed to find uname on a Pyramid OSx when run in the BSD universe. -# (ghazi@noc.rutgers.edu 1994-08-24) -if (test -f /.attbin/uname) >/dev/null 2>&1 ; then - PATH=$PATH:/.attbin ; export PATH -fi - -UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown -UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown -UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown -UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown - -case "${UNAME_SYSTEM}" in -Linux|GNU|GNU/*) - # If the system lacks a compiler, then just pick glibc. - # We could probably try harder. - LIBC=gnu - - eval $set_cc_for_build - cat <<-EOF > $dummy.c - #include <features.h> - #if defined(__UCLIBC__) - LIBC=uclibc - #elif defined(__dietlibc__) - LIBC=dietlibc - #else - LIBC=gnu - #endif - EOF - eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^LIBC' | sed 's, ,,g'` - ;; -esac - -# Note: order is significant - the case branches are not exclusive. - -case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in - *:NetBSD:*:*) - # NetBSD (nbsd) targets should (where applicable) match one or - # more of the tuples: *-*-netbsdelf*, *-*-netbsdaout*, - # *-*-netbsdecoff* and *-*-netbsd*. For targets that recently - # switched to ELF, *-*-netbsd* would select the old - # object file format. This provides both forward - # compatibility and a consistent mechanism for selecting the - # object file format. - # - # Note: NetBSD doesn't particularly care about the vendor - # portion of the name. We always set it to "unknown". - sysctl="sysctl -n hw.machine_arch" - UNAME_MACHINE_ARCH=`(uname -p 2>/dev/null || \ - /sbin/$sysctl 2>/dev/null || \ - /usr/sbin/$sysctl 2>/dev/null || \ - echo unknown)` - case "${UNAME_MACHINE_ARCH}" in - armeb) machine=armeb-unknown ;; - arm*) machine=arm-unknown ;; - sh3el) machine=shl-unknown ;; - sh3eb) machine=sh-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 ;; - esac - # The Operating System including object format, if it has switched - # to ELF recently (or will in the future) and ABI. - case "${UNAME_MACHINE_ARCH}" in - earm*) - os=netbsdelf - ;; - arm*|i386|m68k|ns32k|sh3*|sparc|vax) - eval $set_cc_for_build - if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \ - | grep -q __ELF__ - then - # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout). - # Return netbsd for either. FIX? - os=netbsd - else - os=netbsdelf - fi - ;; - *) - os=netbsd - ;; - 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 - # Debian GNU/NetBSD machines have a different userland, and - # thus, need a distinct triplet. However, they do not need - # kernel version information, so it can be replaced with a - # suitable tag, in the style of linux-gnu. - case "${UNAME_VERSION}" in - Debian*) - release='-gnu' - ;; - *) - release=`echo ${UNAME_RELEASE} | sed -e 's/[-_].*//' | cut -d. -f1,2` - ;; - esac - # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM: - # contains redundant information, the shorter form: - # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used. - echo "${machine}-${os}${release}${abi}" - exit ;; - *:Bitrig:*:*) - UNAME_MACHINE_ARCH=`arch | sed 's/Bitrig.//'` - echo ${UNAME_MACHINE_ARCH}-unknown-bitrig${UNAME_RELEASE} - exit ;; - *:OpenBSD:*:*) - UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'` - echo ${UNAME_MACHINE_ARCH}-unknown-openbsd${UNAME_RELEASE} - exit ;; - *:LibertyBSD:*:*) - UNAME_MACHINE_ARCH=`arch | sed 's/^.*BSD\.//'` - echo ${UNAME_MACHINE_ARCH}-unknown-libertybsd${UNAME_RELEASE} - exit ;; - *:ekkoBSD:*:*) - echo ${UNAME_MACHINE}-unknown-ekkobsd${UNAME_RELEASE} - exit ;; - *:SolidBSD:*:*) - echo ${UNAME_MACHINE}-unknown-solidbsd${UNAME_RELEASE} - exit ;; - macppc:MirBSD:*:*) - echo powerpc-unknown-mirbsd${UNAME_RELEASE} - exit ;; - *:MirBSD:*:*) - echo ${UNAME_MACHINE}-unknown-mirbsd${UNAME_RELEASE} - exit ;; - *:Sortix:*:*) - echo ${UNAME_MACHINE}-unknown-sortix - exit ;; - alpha:OSF1:*:*) - case $UNAME_RELEASE in - *4.0) - UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'` - ;; - *5.*) - UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'` - ;; - esac - # According to Compaq, /usr/sbin/psrinfo has been available on - # OSF/1 and Tru64 systems produced since 1995. I hope that - # covers most systems running today. This code pipes the CPU - # types through head -n 1, so we only detect the type of CPU 0. - ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^ The alpha \(.*\) processor.*$/\1/p' | head -n 1` - case "$ALPHA_CPU_TYPE" in - "EV4 (21064)") - UNAME_MACHINE=alpha ;; - "EV4.5 (21064)") - UNAME_MACHINE=alpha ;; - "LCA4 (21066/21068)") - UNAME_MACHINE=alpha ;; - "EV5 (21164)") - UNAME_MACHINE=alphaev5 ;; - "EV5.6 (21164A)") - UNAME_MACHINE=alphaev56 ;; - "EV5.6 (21164PC)") - UNAME_MACHINE=alphapca56 ;; - "EV5.7 (21164PC)") - UNAME_MACHINE=alphapca57 ;; - "EV6 (21264)") - UNAME_MACHINE=alphaev6 ;; - "EV6.7 (21264A)") - UNAME_MACHINE=alphaev67 ;; - "EV6.8CB (21264C)") - UNAME_MACHINE=alphaev68 ;; - "EV6.8AL (21264B)") - UNAME_MACHINE=alphaev68 ;; - "EV6.8CX (21264D)") - UNAME_MACHINE=alphaev68 ;; - "EV6.9A (21264/EV69A)") - UNAME_MACHINE=alphaev69 ;; - "EV7 (21364)") - UNAME_MACHINE=alphaev7 ;; - "EV7.9 (21364A)") - UNAME_MACHINE=alphaev79 ;; - esac - # A Pn.n version is a patched version. - # A Vn.n version is a released version. - # A Tn.n version is a released field test version. - # A Xn.n version is an unreleased experimental baselevel. - # 1.2 uses "1.2" for uname -r. - 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. - exitcode=$? - trap '' 0 - exit $exitcode ;; - Alpha\ *:Windows_NT*:*) - # How do we know it's Interix rather than the generic POSIX subsystem? - # Should we change UNAME_MACHINE based on the output of uname instead - # of the specific Alpha model? - echo alpha-pc-interix - exit ;; - 21064:Windows_NT:50:3) - echo alpha-dec-winnt3.5 - exit ;; - Amiga*:UNIX_System_V:4.0:*) - echo m68k-unknown-sysv4 - exit ;; - *:[Aa]miga[Oo][Ss]:*:*) - echo ${UNAME_MACHINE}-unknown-amigaos - exit ;; - *:[Mm]orph[Oo][Ss]:*:*) - echo ${UNAME_MACHINE}-unknown-morphos - exit ;; - *:OS/390:*:*) - echo i370-ibm-openedition - exit ;; - *:z/VM:*:*) - echo s390-ibm-zvmoe - exit ;; - *:OS400:*:*) - echo powerpc-ibm-os400 - exit ;; - arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*) - echo arm-acorn-riscix${UNAME_RELEASE} - exit ;; - arm*:riscos:*:*|arm*:RISCOS:*:*) - echo arm-unknown-riscos - exit ;; - SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*) - echo hppa1.1-hitachi-hiuxmpp - exit ;; - Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*) - # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE. - if test "`(/bin/universe) 2>/dev/null`" = att ; then - echo pyramid-pyramid-sysv3 - else - echo pyramid-pyramid-bsd - fi - exit ;; - NILE*:*:*:dcosx) - echo pyramid-pyramid-svr4 - exit ;; - DRS?6000:unix:4.0:6*) - echo sparc-icl-nx6 - exit ;; - DRS?6000:UNIX_SV:4.2*:7* | DRS?6000:isis:4.2*:7*) - case `/usr/bin/uname -p` in - sparc) echo sparc-icl-nx7; exit ;; - esac ;; - s390x:SunOS:*:*) - echo ${UNAME_MACHINE}-ibm-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` - exit ;; - sun4H:SunOS:5.*:*) - echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` - exit ;; - sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*) - echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` - exit ;; - i86pc:AuroraUX:5.*:* | i86xen:AuroraUX:5.*:*) - echo i386-pc-auroraux${UNAME_RELEASE} - exit ;; - i86pc:SunOS:5.*:* | i86xen:SunOS:5.*:*) - eval $set_cc_for_build - SUN_ARCH=i386 - # 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. - # This test works for both compilers. - if [ "$CC_FOR_BUILD" != no_compiler_found ]; then - if (echo '#ifdef __amd64'; echo IS_64BIT_ARCH; echo '#endif') | \ - (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \ - grep IS_64BIT_ARCH >/dev/null - then - SUN_ARCH=x86_64 - fi - fi - echo ${SUN_ARCH}-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` - exit ;; - sun4*:SunOS:6*:*) - # According to config.sub, this is the proper way to canonicalize - # SunOS6. Hard to guess exactly what SunOS6 will be like, but - # it's likely to be more like Solaris than SunOS4. - echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` - exit ;; - sun4*:SunOS:*:*) - case "`/usr/bin/arch -k`" in - Series*|S4*) - UNAME_RELEASE=`uname -v` - ;; - esac - # Japanese Language versions have a version number like `4.1.3-JL'. - echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'` - exit ;; - sun3*:SunOS:*:*) - echo m68k-sun-sunos${UNAME_RELEASE} - exit ;; - sun*:*:4.2BSD:*) - UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null` - test "x${UNAME_RELEASE}" = x && UNAME_RELEASE=3 - case "`/bin/arch`" in - sun3) - echo m68k-sun-sunos${UNAME_RELEASE} - ;; - sun4) - echo sparc-sun-sunos${UNAME_RELEASE} - ;; - esac - exit ;; - aushp:SunOS:*:*) - echo sparc-auspex-sunos${UNAME_RELEASE} - exit ;; - # The situation for MiNT is a little confusing. The machine name - # can be virtually everything (everything which is not - # "atarist" or "atariste" at least should have a processor - # > m68000). The system name ranges from "MiNT" over "FreeMiNT" - # to the lowercase version "mint" (or "freemint"). Finally - # the system name "TOS" denotes a system which is actually not - # MiNT. But MiNT is downward compatible to TOS, so this should - # be no problem. - atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*) - echo m68k-atari-mint${UNAME_RELEASE} - exit ;; - atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*) - echo m68k-atari-mint${UNAME_RELEASE} - exit ;; - *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*) - echo m68k-atari-mint${UNAME_RELEASE} - exit ;; - milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*) - echo m68k-milan-mint${UNAME_RELEASE} - exit ;; - hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*) - echo m68k-hades-mint${UNAME_RELEASE} - exit ;; - *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*) - echo m68k-unknown-mint${UNAME_RELEASE} - exit ;; - m68k:machten:*:*) - echo m68k-apple-machten${UNAME_RELEASE} - exit ;; - powerpc:machten:*:*) - echo powerpc-apple-machten${UNAME_RELEASE} - exit ;; - RISC*:Mach:*:*) - echo mips-dec-mach_bsd4.3 - exit ;; - RISC*:ULTRIX:*:*) - echo mips-dec-ultrix${UNAME_RELEASE} - exit ;; - VAX*:ULTRIX*:*:*) - echo vax-dec-ultrix${UNAME_RELEASE} - exit ;; - 2020:CLIX:*:* | 2430:CLIX:*:*) - echo clipper-intergraph-clix${UNAME_RELEASE} - exit ;; - mips:*:*:UMIPS | mips:*:*:RISCos) - eval $set_cc_for_build - sed 's/^ //' << EOF >$dummy.c -#ifdef __cplusplus -#include <stdio.h> /* for printf() prototype */ - int main (int argc, char *argv[]) { -#else - int main (argc, argv) int argc; char *argv[]; { -#endif - #if defined (host_mips) && defined (MIPSEB) - #if defined (SYSTYPE_SYSV) - printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0); - #endif - #if defined (SYSTYPE_SVR4) - printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0); - #endif - #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD) - printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0); - #endif - #endif - exit (-1); - } -EOF - $CC_FOR_BUILD -o $dummy $dummy.c && - dummyarg=`echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` && - SYSTEM_NAME=`$dummy $dummyarg` && - { echo "$SYSTEM_NAME"; exit; } - echo mips-mips-riscos${UNAME_RELEASE} - exit ;; - Motorola:PowerMAX_OS:*:*) - echo powerpc-motorola-powermax - exit ;; - Motorola:*:4.3:PL8-*) - echo powerpc-harris-powermax - exit ;; - Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*) - echo powerpc-harris-powermax - exit ;; - Night_Hawk:Power_UNIX:*:*) - echo powerpc-harris-powerunix - exit ;; - m88k:CX/UX:7*:*) - echo m88k-harris-cxux7 - exit ;; - m88k:*:4*:R4*) - echo m88k-motorola-sysv4 - exit ;; - m88k:*:3*:R3*) - echo m88k-motorola-sysv3 - exit ;; - AViiON:dgux:*:*) - # DG/UX returns AViiON for all architectures - UNAME_PROCESSOR=`/usr/bin/uname -p` - if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ] - then - if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \ - [ ${TARGET_BINARY_INTERFACE}x = x ] - then - echo m88k-dg-dgux${UNAME_RELEASE} - else - echo m88k-dg-dguxbcs${UNAME_RELEASE} - fi - else - echo i586-dg-dgux${UNAME_RELEASE} - fi - exit ;; - M88*:DolphinOS:*:*) # DolphinOS (SVR3) - echo m88k-dolphin-sysv3 - exit ;; - M88*:*:R3*:*) - # Delta 88k system running SVR3 - echo m88k-motorola-sysv3 - exit ;; - XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3) - echo m88k-tektronix-sysv3 - exit ;; - Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD) - echo m68k-tektronix-bsd - exit ;; - *:IRIX*:*:*) - echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'` - exit ;; - ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX. - echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id - exit ;; # Note that: echo "'`uname -s`'" gives 'AIX ' - i*86:AIX:*:*) - echo i386-ibm-aix - exit ;; - ia64:AIX:*:*) - if [ -x /usr/bin/oslevel ] ; then - IBM_REV=`/usr/bin/oslevel` - else - IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} - fi - echo ${UNAME_MACHINE}-ibm-aix${IBM_REV} - exit ;; - *:AIX:2:3) - if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then - eval $set_cc_for_build - sed 's/^ //' << EOF >$dummy.c - #include <sys/systemcfg.h> - - main() - { - if (!__power_pc()) - exit(1); - puts("powerpc-ibm-aix3.2.5"); - exit(0); - } -EOF - if $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` - then - echo "$SYSTEM_NAME" - else - echo rs6000-ibm-aix3.2.5 - fi - elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then - echo rs6000-ibm-aix3.2.4 - else - echo rs6000-ibm-aix3.2 - fi - exit ;; - *:AIX:*:[4567]) - IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'` - if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then - IBM_ARCH=rs6000 - else - IBM_ARCH=powerpc - fi - if [ -x /usr/bin/lslpp ] ; then - IBM_REV=`/usr/bin/lslpp -Lqc bos.rte.libc | - awk -F: '{ print $3 }' | sed s/[0-9]*$/0/` - else - IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} - fi - echo ${IBM_ARCH}-ibm-aix${IBM_REV} - exit ;; - *:AIX:*:*) - echo rs6000-ibm-aix - exit ;; - ibmrt:4.4BSD:*|romp-ibm:BSD:*) - echo romp-ibm-bsd4.4 - exit ;; - ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC BSD and - echo romp-ibm-bsd${UNAME_RELEASE} # 4.3 with uname added to - exit ;; # report: romp-ibm BSD 4.3 - *:BOSX:*:*) - echo rs6000-bull-bosx - exit ;; - DPX/2?00:B.O.S.:*:*) - echo m68k-bull-sysv3 - exit ;; - 9000/[34]??:4.3bsd:1.*:*) - echo m68k-hp-bsd - exit ;; - hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*) - echo m68k-hp-bsd4.4 - exit ;; - 9000/[34678]??:HP-UX:*:*) - HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` - case "${UNAME_MACHINE}" in - 9000/31? ) HP_ARCH=m68000 ;; - 9000/[34]?? ) HP_ARCH=m68k ;; - 9000/[678][0-9][0-9]) - if [ -x /usr/bin/getconf ]; then - sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null` - sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null` - case "${sc_cpu_version}" in - 523) HP_ARCH=hppa1.0 ;; # CPU_PA_RISC1_0 - 528) HP_ARCH=hppa1.1 ;; # CPU_PA_RISC1_1 - 532) # CPU_PA_RISC2_0 - case "${sc_kernel_bits}" in - 32) HP_ARCH=hppa2.0n ;; - 64) HP_ARCH=hppa2.0w ;; - '') HP_ARCH=hppa2.0 ;; # HP-UX 10.20 - esac ;; - esac - fi - if [ "${HP_ARCH}" = "" ]; then - eval $set_cc_for_build - sed 's/^ //' << EOF >$dummy.c - - #define _HPUX_SOURCE - #include <stdlib.h> - #include <unistd.h> - - int main () - { - #if defined(_SC_KERNEL_BITS) - long bits = sysconf(_SC_KERNEL_BITS); - #endif - long cpu = sysconf (_SC_CPU_VERSION); - - switch (cpu) - { - case CPU_PA_RISC1_0: puts ("hppa1.0"); break; - case CPU_PA_RISC1_1: puts ("hppa1.1"); break; - case CPU_PA_RISC2_0: - #if defined(_SC_KERNEL_BITS) - switch (bits) - { - case 64: puts ("hppa2.0w"); break; - case 32: puts ("hppa2.0n"); break; - default: puts ("hppa2.0"); break; - } break; - #else /* !defined(_SC_KERNEL_BITS) */ - puts ("hppa2.0"); break; - #endif - default: puts ("hppa1.0"); break; - } - exit (0); - } -EOF - (CCOPTS="" $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy` - test -z "$HP_ARCH" && HP_ARCH=hppa - fi ;; - esac - if [ ${HP_ARCH} = hppa2.0w ] - then - eval $set_cc_for_build - - # hppa2.0w-hp-hpux* has a 64-bit kernel and a compiler generating - # 32-bit code. hppa64-hp-hpux* has the same kernel and a compiler - # generating 64-bit code. GNU and HP use different nomenclature: - # - # $ CC_FOR_BUILD=cc ./config.guess - # => hppa2.0w-hp-hpux11.23 - # $ CC_FOR_BUILD="cc +DA2.0w" ./config.guess - # => hppa64-hp-hpux11.23 - - if echo __LP64__ | (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | - grep -q __LP64__ - then - HP_ARCH=hppa2.0w - else - HP_ARCH=hppa64 - fi - fi - echo ${HP_ARCH}-hp-hpux${HPUX_REV} - exit ;; - ia64:HP-UX:*:*) - HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` - echo ia64-hp-hpux${HPUX_REV} - exit ;; - 3050*:HI-UX:*:*) - eval $set_cc_for_build - sed 's/^ //' << EOF >$dummy.c - #include <unistd.h> - int - main () - { - long cpu = sysconf (_SC_CPU_VERSION); - /* The order matters, because CPU_IS_HP_MC68K erroneously returns - true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct - results, however. */ - if (CPU_IS_PA_RISC (cpu)) - { - switch (cpu) - { - case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break; - case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break; - case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break; - default: puts ("hppa-hitachi-hiuxwe2"); break; - } - } - else if (CPU_IS_HP_MC68K (cpu)) - puts ("m68k-hitachi-hiuxwe2"); - else puts ("unknown-hitachi-hiuxwe2"); - exit (0); - } -EOF - $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` && - { echo "$SYSTEM_NAME"; exit; } - echo unknown-hitachi-hiuxwe2 - exit ;; - 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* ) - echo hppa1.1-hp-bsd - exit ;; - 9000/8??:4.3bsd:*:*) - echo hppa1.0-hp-bsd - exit ;; - *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*) - echo hppa1.0-hp-mpeix - exit ;; - hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* ) - echo hppa1.1-hp-osf - exit ;; - hp8??:OSF1:*:*) - echo hppa1.0-hp-osf - exit ;; - i*86:OSF1:*:*) - if [ -x /usr/sbin/sysversion ] ; then - echo ${UNAME_MACHINE}-unknown-osf1mk - else - echo ${UNAME_MACHINE}-unknown-osf1 - fi - exit ;; - parisc*:Lites*:*:*) - echo hppa1.1-hp-lites - exit ;; - C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*) - echo c1-convex-bsd - exit ;; - C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*) - if getsysinfo -f scalar_acc - then echo c32-convex-bsd - else echo c2-convex-bsd - fi - exit ;; - C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*) - echo c34-convex-bsd - exit ;; - C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*) - echo c38-convex-bsd - exit ;; - C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*) - echo c4-convex-bsd - exit ;; - CRAY*Y-MP:*:*:*) - echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' - exit ;; - CRAY*[A-Z]90:*:*:*) - echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \ - | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \ - -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \ - -e 's/\.[^.]*$/.X/' - exit ;; - CRAY*TS:*:*:*) - echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' - exit ;; - CRAY*T3E:*:*:*) - echo alphaev5-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' - exit ;; - CRAY*SV1:*:*:*) - echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' - exit ;; - *:UNICOS/mp:*:*) - echo craynv-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' - exit ;; - F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*) - FUJITSU_PROC=`uname -m | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz` - FUJITSU_SYS=`uname -p | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/\///'` - FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'` - echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" - exit ;; - 5000:UNIX_System_V:4.*:*) - FUJITSU_SYS=`uname -p | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/\///'` - FUJITSU_REL=`echo ${UNAME_RELEASE} | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/ /_/'` - echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" - exit ;; - i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*) - echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE} - exit ;; - sparc*:BSD/OS:*:*) - echo sparc-unknown-bsdi${UNAME_RELEASE} - exit ;; - *:BSD/OS:*:*) - echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE} - exit ;; - *:FreeBSD:*:*) - UNAME_PROCESSOR=`/usr/bin/uname -p` - case ${UNAME_PROCESSOR} in - amd64) - echo x86_64-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; - *) - echo ${UNAME_PROCESSOR}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; - esac - exit ;; - i*:CYGWIN*:*) - echo ${UNAME_MACHINE}-pc-cygwin - exit ;; - *:MINGW64*:*) - echo ${UNAME_MACHINE}-pc-mingw64 - exit ;; - *:MINGW*:*) - echo ${UNAME_MACHINE}-pc-mingw32 - exit ;; - *:MSYS*:*) - echo ${UNAME_MACHINE}-pc-msys - exit ;; - i*:windows32*:*) - # uname -m includes "-pc" on this system. - echo ${UNAME_MACHINE}-mingw32 - exit ;; - i*:PW*:*) - echo ${UNAME_MACHINE}-pc-pw32 - exit ;; - *:Interix*:*) - case ${UNAME_MACHINE} in - x86) - echo i586-pc-interix${UNAME_RELEASE} - exit ;; - authenticamd | genuineintel | EM64T) - echo x86_64-unknown-interix${UNAME_RELEASE} - exit ;; - IA64) - echo ia64-unknown-interix${UNAME_RELEASE} - exit ;; - esac ;; - [345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*) - echo i${UNAME_MACHINE}-pc-mks - exit ;; - 8664:Windows_NT:*) - echo x86_64-pc-mks - exit ;; - i*:Windows_NT*:* | Pentium*:Windows_NT*:*) - # How do we know it's Interix rather than the generic POSIX subsystem? - # It also conflicts with pre-2.0 versions of AT&T UWIN. Should we - # UNAME_MACHINE based on the output of uname instead of i386? - echo i586-pc-interix - exit ;; - i*:UWIN*:*) - echo ${UNAME_MACHINE}-pc-uwin - exit ;; - amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*) - echo x86_64-unknown-cygwin - exit ;; - p*:CYGWIN*:*) - echo powerpcle-unknown-cygwin - exit ;; - prep*:SunOS:5.*:*) - echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` - exit ;; - *:GNU:*:*) - # the GNU system - echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-${LIBC}`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'` - exit ;; - *:GNU/*:*:*) - # other systems with GNU libc and userland - echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr "[:upper:]" "[:lower:]"``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-${LIBC} - exit ;; - i*86:Minix:*:*) - echo ${UNAME_MACHINE}-pc-minix - exit ;; - aarch64:Linux:*:*) - echo ${UNAME_MACHINE}-unknown-linux-${LIBC} - exit ;; - aarch64_be:Linux:*:*) - UNAME_MACHINE=aarch64_be - echo ${UNAME_MACHINE}-unknown-linux-${LIBC} - exit ;; - alpha:Linux:*:*) - case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in - EV5) UNAME_MACHINE=alphaev5 ;; - EV56) UNAME_MACHINE=alphaev56 ;; - PCA56) UNAME_MACHINE=alphapca56 ;; - PCA57) UNAME_MACHINE=alphapca56 ;; - EV6) UNAME_MACHINE=alphaev6 ;; - EV67) UNAME_MACHINE=alphaev67 ;; - EV68*) UNAME_MACHINE=alphaev68 ;; - esac - objdump --private-headers /bin/sh | grep -q ld.so.1 - if test "$?" = 0 ; then LIBC=gnulibc1 ; fi - echo ${UNAME_MACHINE}-unknown-linux-${LIBC} - exit ;; - arc:Linux:*:* | arceb:Linux:*:*) - echo ${UNAME_MACHINE}-unknown-linux-${LIBC} - exit ;; - arm*:Linux:*:*) - eval $set_cc_for_build - if echo __ARM_EABI__ | $CC_FOR_BUILD -E - 2>/dev/null \ - | grep -q __ARM_EABI__ - then - echo ${UNAME_MACHINE}-unknown-linux-${LIBC} - else - if echo __ARM_PCS_VFP | $CC_FOR_BUILD -E - 2>/dev/null \ - | grep -q __ARM_PCS_VFP - then - echo ${UNAME_MACHINE}-unknown-linux-${LIBC}eabi - else - echo ${UNAME_MACHINE}-unknown-linux-${LIBC}eabihf - fi - fi - exit ;; - avr32*:Linux:*:*) - echo ${UNAME_MACHINE}-unknown-linux-${LIBC} - exit ;; - cris:Linux:*:*) - echo ${UNAME_MACHINE}-axis-linux-${LIBC} - exit ;; - crisv32:Linux:*:*) - echo ${UNAME_MACHINE}-axis-linux-${LIBC} - exit ;; - e2k:Linux:*:*) - echo ${UNAME_MACHINE}-unknown-linux-${LIBC} - exit ;; - frv:Linux:*:*) - echo ${UNAME_MACHINE}-unknown-linux-${LIBC} - exit ;; - hexagon:Linux:*:*) - echo ${UNAME_MACHINE}-unknown-linux-${LIBC} - exit ;; - i*86:Linux:*:*) - echo ${UNAME_MACHINE}-pc-linux-${LIBC} - exit ;; - ia64:Linux:*:*) - echo ${UNAME_MACHINE}-unknown-linux-${LIBC} - exit ;; - k1om:Linux:*:*) - echo ${UNAME_MACHINE}-unknown-linux-${LIBC} - exit ;; - m32r*:Linux:*:*) - echo ${UNAME_MACHINE}-unknown-linux-${LIBC} - exit ;; - m68*:Linux:*:*) - echo ${UNAME_MACHINE}-unknown-linux-${LIBC} - exit ;; - mips:Linux:*:* | mips64:Linux:*:*) - eval $set_cc_for_build - sed 's/^ //' << EOF >$dummy.c - #undef CPU - #undef ${UNAME_MACHINE} - #undef ${UNAME_MACHINE}el - #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) - CPU=${UNAME_MACHINE}el - #else - #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB) - CPU=${UNAME_MACHINE} - #else - CPU= - #endif - #endif -EOF - eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^CPU'` - test x"${CPU}" != x && { echo "${CPU}-unknown-linux-${LIBC}"; exit; } - ;; - mips64el:Linux:*:*) - echo ${UNAME_MACHINE}-unknown-linux-${LIBC} - exit ;; - openrisc*:Linux:*:*) - echo or1k-unknown-linux-${LIBC} - exit ;; - or32:Linux:*:* | or1k*:Linux:*:*) - echo ${UNAME_MACHINE}-unknown-linux-${LIBC} - exit ;; - padre:Linux:*:*) - echo sparc-unknown-linux-${LIBC} - exit ;; - parisc64:Linux:*:* | hppa64:Linux:*:*) - echo hppa64-unknown-linux-${LIBC} - exit ;; - parisc:Linux:*:* | hppa:Linux:*:*) - # Look for CPU level - case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in - PA7*) echo hppa1.1-unknown-linux-${LIBC} ;; - PA8*) echo hppa2.0-unknown-linux-${LIBC} ;; - *) echo hppa-unknown-linux-${LIBC} ;; - esac - exit ;; - ppc64:Linux:*:*) - echo powerpc64-unknown-linux-${LIBC} - exit ;; - ppc:Linux:*:*) - echo powerpc-unknown-linux-${LIBC} - exit ;; - ppc64le:Linux:*:*) - echo powerpc64le-unknown-linux-${LIBC} - exit ;; - ppcle:Linux:*:*) - echo powerpcle-unknown-linux-${LIBC} - exit ;; - riscv32:Linux:*:* | riscv64:Linux:*:*) - echo ${UNAME_MACHINE}-unknown-linux-${LIBC} - exit ;; - s390:Linux:*:* | s390x:Linux:*:*) - echo ${UNAME_MACHINE}-ibm-linux-${LIBC} - exit ;; - sh64*:Linux:*:*) - echo ${UNAME_MACHINE}-unknown-linux-${LIBC} - exit ;; - sh*:Linux:*:*) - echo ${UNAME_MACHINE}-unknown-linux-${LIBC} - exit ;; - sparc:Linux:*:* | sparc64:Linux:*:*) - echo ${UNAME_MACHINE}-unknown-linux-${LIBC} - exit ;; - tile*:Linux:*:*) - echo ${UNAME_MACHINE}-unknown-linux-${LIBC} - exit ;; - vax:Linux:*:*) - echo ${UNAME_MACHINE}-dec-linux-${LIBC} - exit ;; - x86_64:Linux:*:*) - echo ${UNAME_MACHINE}-pc-linux-${LIBC} - exit ;; - xtensa*:Linux:*:*) - echo ${UNAME_MACHINE}-unknown-linux-${LIBC} - exit ;; - i*86:DYNIX/ptx:4*:*) - # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there. - # earlier versions are messed up and put the nodename in both - # sysname and nodename. - echo i386-sequent-sysv4 - exit ;; - i*86:UNIX_SV:4.2MP:2.*) - # Unixware is an offshoot of SVR4, but it has its own version - # number series starting with 2... - # I am not positive that other SVR4 systems won't match this, - # I just have to hope. -- rms. - # Use sysv4.2uw... so that sysv4* matches it. - echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION} - exit ;; - i*86:OS/2:*:*) - # If we were able to find `uname', then EMX Unix compatibility - # is probably installed. - echo ${UNAME_MACHINE}-pc-os2-emx - exit ;; - i*86:XTS-300:*:STOP) - echo ${UNAME_MACHINE}-unknown-stop - exit ;; - i*86:atheos:*:*) - echo ${UNAME_MACHINE}-unknown-atheos - exit ;; - i*86:syllable:*:*) - echo ${UNAME_MACHINE}-pc-syllable - exit ;; - i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.[02]*:*) - echo i386-unknown-lynxos${UNAME_RELEASE} - exit ;; - i*86:*DOS:*:*) - echo ${UNAME_MACHINE}-pc-msdosdjgpp - exit ;; - i*86:*:4.*:* | i*86:SYSTEM_V:4.*:*) - UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'` - if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then - echo ${UNAME_MACHINE}-univel-sysv${UNAME_REL} - else - echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL} - fi - exit ;; - i*86:*:5:[678]*) - # UnixWare 7.x, OpenUNIX and OpenServer 6. - case `/bin/uname -X | grep "^Machine"` in - *486*) UNAME_MACHINE=i486 ;; - *Pentium) UNAME_MACHINE=i586 ;; - *Pent*|*Celeron) UNAME_MACHINE=i686 ;; - esac - echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION} - exit ;; - i*86:*:3.2:*) - if test -f /usr/options/cb.name; then - UNAME_REL=`sed -n 's/.*Version //p' </usr/options/cb.name` - echo ${UNAME_MACHINE}-pc-isc$UNAME_REL - elif /bin/uname -X 2>/dev/null >/dev/null ; then - UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')` - (/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486 - (/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \ - && UNAME_MACHINE=i586 - (/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \ - && UNAME_MACHINE=i686 - (/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \ - && UNAME_MACHINE=i686 - echo ${UNAME_MACHINE}-pc-sco$UNAME_REL - else - echo ${UNAME_MACHINE}-pc-sysv32 - fi - exit ;; - pc:*:*:*) - # Left here for compatibility: - # uname -m prints for DJGPP always 'pc', but it prints nothing about - # the processor, so we play safe by assuming i586. - # Note: whatever this is, it MUST be the same as what config.sub - # prints for the "djgpp" host, or else GDB configure will decide that - # this is a cross-build. - echo i586-pc-msdosdjgpp - exit ;; - Intel:Mach:3*:*) - echo i386-pc-mach3 - exit ;; - paragon:*:*:*) - echo i860-intel-osf1 - exit ;; - i860:*:4.*:*) # i860-SVR4 - if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then - echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4 - else # Add other i860-SVR4 vendors below as they are discovered. - echo i860-unknown-sysv${UNAME_RELEASE} # Unknown i860-SVR4 - fi - exit ;; - mini*:CTIX:SYS*5:*) - # "miniframe" - echo m68010-convergent-sysv - exit ;; - mc68k:UNIX:SYSTEM5:3.51m) - echo m68k-convergent-sysv - exit ;; - M680?0:D-NIX:5.3:*) - echo m68k-diab-dnix - exit ;; - M68*:*:R3V[5678]*:*) - test -r /sysV68 && { echo 'm68k-motorola-sysv'; exit; } ;; - 3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0 | S7501*:*:4.0:3.0) - OS_REL='' - test -r /etc/.relid \ - && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` - /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ - && { echo i486-ncr-sysv4.3${OS_REL}; exit; } - /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ - && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;; - 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*) - /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ - && { echo i486-ncr-sysv4; exit; } ;; - NCR*:*:4.2:* | MPRAS*:*:4.2:*) - OS_REL='.3' - test -r /etc/.relid \ - && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` - /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ - && { echo i486-ncr-sysv4.3${OS_REL}; exit; } - /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ - && { echo i586-ncr-sysv4.3${OS_REL}; exit; } - /bin/uname -p 2>/dev/null | /bin/grep pteron >/dev/null \ - && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;; - m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*) - echo m68k-unknown-lynxos${UNAME_RELEASE} - exit ;; - mc68030:UNIX_System_V:4.*:*) - echo m68k-atari-sysv4 - exit ;; - TSUNAMI:LynxOS:2.*:*) - echo sparc-unknown-lynxos${UNAME_RELEASE} - exit ;; - rs6000:LynxOS:2.*:*) - echo rs6000-unknown-lynxos${UNAME_RELEASE} - exit ;; - PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.[02]*:*) - echo powerpc-unknown-lynxos${UNAME_RELEASE} - exit ;; - SM[BE]S:UNIX_SV:*:*) - echo mips-dde-sysv${UNAME_RELEASE} - exit ;; - RM*:ReliantUNIX-*:*:*) - echo mips-sni-sysv4 - exit ;; - RM*:SINIX-*:*:*) - echo mips-sni-sysv4 - exit ;; - *:SINIX-*:*:*) - if uname -p 2>/dev/null >/dev/null ; then - UNAME_MACHINE=`(uname -p) 2>/dev/null` - echo ${UNAME_MACHINE}-sni-sysv4 - else - echo ns32k-sni-sysv - fi - exit ;; - PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort - # says <Richard.M.Bartel@ccMail.Census.GOV> - echo i586-unisys-sysv4 - exit ;; - *:UNIX_System_V:4*:FTX*) - # From Gerald Hewes <hewes@openmarket.com>. - # How about differentiating between stratus architectures? -djm - echo hppa1.1-stratus-sysv4 - exit ;; - *:*:*:FTX*) - # From seanf@swdc.stratus.com. - echo i860-stratus-sysv4 - exit ;; - i*86:VOS:*:*) - # From Paul.Green@stratus.com. - echo ${UNAME_MACHINE}-stratus-vos - exit ;; - *:VOS:*:*) - # From Paul.Green@stratus.com. - echo hppa1.1-stratus-vos - exit ;; - mc68*:A/UX:*:*) - echo m68k-apple-aux${UNAME_RELEASE} - exit ;; - news*:NEWS-OS:6*:*) - echo mips-sony-newsos6 - exit ;; - R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*) - if [ -d /usr/nec ]; then - echo mips-nec-sysv${UNAME_RELEASE} - else - echo mips-unknown-sysv${UNAME_RELEASE} - fi - exit ;; - BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only. - echo powerpc-be-beos - exit ;; - BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only. - echo powerpc-apple-beos - exit ;; - BePC:BeOS:*:*) # BeOS running on Intel PC compatible. - echo i586-pc-beos - exit ;; - BePC:Haiku:*:*) # Haiku running on Intel PC compatible. - echo i586-pc-haiku - exit ;; - x86_64:Haiku:*:*) - echo x86_64-unknown-haiku - exit ;; - SX-4:SUPER-UX:*:*) - echo sx4-nec-superux${UNAME_RELEASE} - exit ;; - SX-5:SUPER-UX:*:*) - echo sx5-nec-superux${UNAME_RELEASE} - exit ;; - SX-6:SUPER-UX:*:*) - echo sx6-nec-superux${UNAME_RELEASE} - exit ;; - SX-7:SUPER-UX:*:*) - echo sx7-nec-superux${UNAME_RELEASE} - exit ;; - SX-8:SUPER-UX:*:*) - echo sx8-nec-superux${UNAME_RELEASE} - exit ;; - SX-8R:SUPER-UX:*:*) - echo sx8r-nec-superux${UNAME_RELEASE} - exit ;; - SX-ACE:SUPER-UX:*:*) - echo sxace-nec-superux${UNAME_RELEASE} - exit ;; - Power*:Rhapsody:*:*) - echo powerpc-apple-rhapsody${UNAME_RELEASE} - exit ;; - *:Rhapsody:*:*) - echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE} - exit ;; - *:Darwin:*:*) - UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown - eval $set_cc_for_build - if test "$UNAME_PROCESSOR" = unknown ; then - UNAME_PROCESSOR=powerpc - fi - if test `echo "$UNAME_RELEASE" | sed -e 's/\..*//'` -le 10 ; then - if [ "$CC_FOR_BUILD" != no_compiler_found ]; then - if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \ - (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \ - grep IS_64BIT_ARCH >/dev/null - then - case $UNAME_PROCESSOR in - i386) UNAME_PROCESSOR=x86_64 ;; - powerpc) UNAME_PROCESSOR=powerpc64 ;; - esac - fi - fi - elif test "$UNAME_PROCESSOR" = i386 ; then - # Avoid executing cc on OS X 10.9, as it ships with a stub - # that puts up a graphical alert prompting to install - # developer tools. Any system running Mac OS X 10.7 or - # later (Darwin 11 and later) is required to have a 64-bit - # processor. This is not true of the ARM version of Darwin - # that Apple uses in portable devices. - UNAME_PROCESSOR=x86_64 - fi - echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE} - exit ;; - *:procnto*:*:* | *:QNX:[0123456789]*:*) - UNAME_PROCESSOR=`uname -p` - if test "$UNAME_PROCESSOR" = x86; then - UNAME_PROCESSOR=i386 - UNAME_MACHINE=pc - fi - echo ${UNAME_PROCESSOR}-${UNAME_MACHINE}-nto-qnx${UNAME_RELEASE} - exit ;; - *:QNX:*:4*) - echo i386-pc-qnx - exit ;; - NEO-?:NONSTOP_KERNEL:*:*) - echo neo-tandem-nsk${UNAME_RELEASE} - exit ;; - NSE-*:NONSTOP_KERNEL:*:*) - echo nse-tandem-nsk${UNAME_RELEASE} - exit ;; - NSR-?:NONSTOP_KERNEL:*:*) - echo nsr-tandem-nsk${UNAME_RELEASE} - exit ;; - *:NonStop-UX:*:*) - echo mips-compaq-nonstopux - exit ;; - BS2000:POSIX*:*:*) - echo bs2000-siemens-sysv - exit ;; - DS/*:UNIX_System_V:*:*) - echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE} - exit ;; - *:Plan9:*:*) - # "uname -m" is not consistent, so use $cputype instead. 386 - # is converted to i386 for consistency with other x86 - # operating systems. - if test "$cputype" = 386; then - UNAME_MACHINE=i386 - else - UNAME_MACHINE="$cputype" - fi - echo ${UNAME_MACHINE}-unknown-plan9 - exit ;; - *:TOPS-10:*:*) - echo pdp10-unknown-tops10 - exit ;; - *:TENEX:*:*) - echo pdp10-unknown-tenex - exit ;; - KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*) - echo pdp10-dec-tops20 - exit ;; - XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*) - echo pdp10-xkl-tops20 - exit ;; - *:TOPS-20:*:*) - echo pdp10-unknown-tops20 - exit ;; - *:ITS:*:*) - echo pdp10-unknown-its - exit ;; - SEI:*:*:SEIUX) - echo mips-sei-seiux${UNAME_RELEASE} - exit ;; - *:DragonFly:*:*) - echo ${UNAME_MACHINE}-unknown-dragonfly`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` - exit ;; - *:*VMS:*:*) - UNAME_MACHINE=`(uname -p) 2>/dev/null` - case "${UNAME_MACHINE}" in - A*) echo alpha-dec-vms ; exit ;; - I*) echo ia64-dec-vms ; exit ;; - V*) echo vax-dec-vms ; exit ;; - esac ;; - *:XENIX:*:SysV) - echo i386-pc-xenix - exit ;; - i*86:skyos:*:*) - echo ${UNAME_MACHINE}-pc-skyos`echo ${UNAME_RELEASE} | sed -e 's/ .*$//'` - exit ;; - i*86:rdos:*:*) - echo ${UNAME_MACHINE}-pc-rdos - exit ;; - i*86:AROS:*:*) - echo ${UNAME_MACHINE}-pc-aros - exit ;; - x86_64:VMkernel:*:*) - echo ${UNAME_MACHINE}-unknown-esx - exit ;; - amd64:Isilon\ OneFS:*:*) - echo x86_64-unknown-onefs - exit ;; -esac - -cat >&2 <<EOF -$0: unable to guess system type - -This script (version $timestamp), has failed to recognize the -operating system you are using. If your script is old, overwrite -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 -and - http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub - -If $0 has already been updated, send the following data and any -information you think might be pertinent to config-patches@gnu.org to -provide the necessary information to handle your system. - -config.guess timestamp = $timestamp - -uname -m = `(uname -m) 2>/dev/null || echo unknown` -uname -r = `(uname -r) 2>/dev/null || echo unknown` -uname -s = `(uname -s) 2>/dev/null || echo unknown` -uname -v = `(uname -v) 2>/dev/null || echo unknown` - -/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null` -/bin/uname -X = `(/bin/uname -X) 2>/dev/null` - -hostinfo = `(hostinfo) 2>/dev/null` -/bin/universe = `(/bin/universe) 2>/dev/null` -/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null` -/bin/arch = `(/bin/arch) 2>/dev/null` -/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null` -/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null` - -UNAME_MACHINE = ${UNAME_MACHINE} -UNAME_RELEASE = ${UNAME_RELEASE} -UNAME_SYSTEM = ${UNAME_SYSTEM} -UNAME_VERSION = ${UNAME_VERSION} -EOF - -exit 1 - -# Local variables: -# eval: (add-hook 'write-file-hooks 'time-stamp) -# time-stamp-start: "timestamp='" -# time-stamp-format: "%:y-%02m-%02d" -# time-stamp-end: "'" -# End: ->>>>>>> main diff --git a/contrib/jemalloc/build-aux/config.sub b/contrib/jemalloc/build-aux/config.sub index 099dab005a9a..b0f8492348d7 100755 --- a/contrib/jemalloc/build-aux/config.sub +++ b/contrib/jemalloc/build-aux/config.sub @@ -1,4 +1,3 @@ -<<<<<<< HEAD #! /bin/sh # Configuration validation subroutine script. # Copyright 1992-2021 Free Software Foundation, Inc. @@ -1854,1831 +1853,3 @@ exit # time-stamp-format: "%:y-%02m-%02d" # time-stamp-end: "'" # End: -||||||| dec341af7695 -======= -#! /bin/sh -# Configuration validation subroutine script. -# Copyright 1992-2016 Free Software Foundation, Inc. - -timestamp='2016-11-04' - -# 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 -# the Free Software Foundation; either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, see <http://www.gnu.org/licenses/>. -# -# As a special exception to the GNU General Public License, if you -# distribute this file as part of a program that contains a -# configuration script generated by Autoconf, you may include it under -# the same distribution terms that you use for the rest of that -# program. This Exception is an additional permission under section 7 -# of the GNU General Public License, version 3 ("GPLv3"). - - -# Please send patches to <config-patches@gnu.org>. -# -# Configuration subroutine to validate and canonicalize a configuration type. -# Supply the specified configuration type as an argument. -# If it is invalid, we print an error message on stderr and exit with code 1. -# Otherwise, we print the canonical config type on stdout and succeed. - -# 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 - -# This file is supposed to be the same for all GNU packages -# and recognize all the CPU types, system types and aliases -# that are meaningful with *any* GNU software. -# Each package is responsible for reporting which valid configurations -# it does not support. The user should be able to distinguish -# a failure to support a valid configuration from a meaningless -# configuration. - -# The goal of this file is to map all the various variations of a given -# machine specification into a single specification in the form: -# CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM -# or in some cases, the newer four-part form: -# CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM -# It is wrong to echo any other type of specification. - -me=`echo "$0" | sed -e 's,.*/,,'` - -usage="\ -Usage: $0 [OPTION] CPU-MFR-OPSYS or ALIAS - -Canonicalize a configuration name. - -Operation modes: - -h, --help print this help, then exit - -t, --time-stamp print date of last modification, then exit - -v, --version print version number, then exit - -Report bugs and patches to <config-patches@gnu.org>." - -version="\ -GNU config.sub ($timestamp) - -Copyright 1992-2016 Free Software Foundation, Inc. - -This is free software; see the source for copying conditions. There is NO -warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." - -help=" -Try \`$me --help' for more information." - -# Parse command line -while test $# -gt 0 ; do - case $1 in - --time-stamp | --time* | -t ) - echo "$timestamp" ; exit ;; - --version | -v ) - echo "$version" ; exit ;; - --help | --h* | -h ) - echo "$usage"; exit ;; - -- ) # Stop option processing - shift; break ;; - - ) # Use stdin as input. - break ;; - -* ) - echo "$me: invalid option $1$help" - exit 1 ;; - - *local*) - # First pass through any local machine types. - echo $1 - exit ;; - - * ) - break ;; - esac -done - -case $# in - 0) echo "$me: missing argument$help" >&2 - exit 1;; - 1) ;; - *) echo "$me: too many arguments$help" >&2 - exit 1;; -esac - -# Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any). -# Here we must recognize all the valid KERNEL-OS combinations. -maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'` -case $maybe_os in - nto-qnx* | linux-gnu* | linux-android* | linux-dietlibc | linux-newlib* | \ - linux-musl* | linux-uclibc* | uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | \ - knetbsd*-gnu* | netbsd*-gnu* | netbsd*-eabi* | \ - kopensolaris*-gnu* | cloudabi*-eabi* | \ - storm-chaos* | os2-emx* | rtmk-nova*) - os=-$maybe_os - basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'` - ;; - android-linux) - os=-linux-android - basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`-unknown - ;; - *) - basic_machine=`echo $1 | sed 's/-[^-]*$//'` - if [ $basic_machine != $1 ] - then os=`echo $1 | sed 's/.*-/-/'` - else os=; fi - ;; -esac - -### Let's recognize common machines as not being operating systems so -### that things like config.sub decstation-3100 work. We also -### recognize some manufacturers as not being operating systems, so we -### can provide default operating systems below. -case $os in - -sun*os*) - # Prevent following clause from handling this invalid input. - ;; - -dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \ - -att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \ - -unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \ - -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\ - -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \ - -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \ - -apple | -axis | -knuth | -cray | -microblaze*) - os= - basic_machine=$1 - ;; - -bluegene*) - os=-cnk - ;; - -sim | -cisco | -oki | -wec | -winbond) - os= - basic_machine=$1 - ;; - -scout) - ;; - -wrs) - os=-vxworks - basic_machine=$1 - ;; - -chorusos*) - os=-chorusos - basic_machine=$1 - ;; - -chorusrdb) - os=-chorusrdb - basic_machine=$1 - ;; - -hiux*) - os=-hiuxwe2 - ;; - -sco6) - os=-sco5v6 - basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` - ;; - -sco5) - os=-sco3.2v5 - basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` - ;; - -sco4) - os=-sco3.2v4 - basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` - ;; - -sco3.2.[4-9]*) - os=`echo $os | sed -e 's/sco3.2./sco3.2v/'` - basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` - ;; - -sco3.2v[4-9]*) - # Don't forget version if it is 3.2v4 or newer. - basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` - ;; - -sco5v6*) - # Don't forget version if it is 3.2v4 or newer. - basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` - ;; - -sco*) - os=-sco3.2v2 - basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` - ;; - -udk*) - basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` - ;; - -isc) - os=-isc2.2 - basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` - ;; - -clix*) - basic_machine=clipper-intergraph - ;; - -isc*) - basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` - ;; - -lynx*178) - os=-lynxos178 - ;; - -lynx*5) - os=-lynxos5 - ;; - -lynx*) - os=-lynxos - ;; - -ptx*) - basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'` - ;; - -windowsnt*) - os=`echo $os | sed -e 's/windowsnt/winnt/'` - ;; - -psos*) - os=-psos - ;; - -mint | -mint[0-9]*) - basic_machine=m68k-atari - os=-mint - ;; -esac - -# Decode aliases for certain CPU-COMPANY combinations. -case $basic_machine in - # Recognize the basic CPU types without company name. - # Some are omitted here because they have special meanings below. - 1750a | 580 \ - | a29k \ - | aarch64 | aarch64_be \ - | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \ - | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \ - | am33_2.0 \ - | arc | arceb \ - | arm | arm[bl]e | arme[lb] | armv[2-8] | armv[3-8][lb] | armv7[arm] \ - | avr | avr32 \ - | ba \ - | be32 | be64 \ - | bfin \ - | c4x | c8051 | clipper \ - | d10v | d30v | dlx | dsp16xx \ - | e2k | epiphany \ - | fido | fr30 | frv | ft32 \ - | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \ - | hexagon \ - | i370 | i860 | i960 | ia64 \ - | ip2k | iq2000 \ - | k1om \ - | le32 | le64 \ - | lm32 \ - | m32c | m32r | m32rle | m68000 | m68k | m88k \ - | maxq | mb | microblaze | microblazeel | mcore | mep | metag \ - | mips | mipsbe | mipseb | mipsel | mipsle \ - | mips16 \ - | mips64 | mips64el \ - | mips64octeon | mips64octeonel \ - | mips64orion | mips64orionel \ - | mips64r5900 | mips64r5900el \ - | mips64vr | mips64vrel \ - | mips64vr4100 | mips64vr4100el \ - | mips64vr4300 | mips64vr4300el \ - | mips64vr5000 | mips64vr5000el \ - | mips64vr5900 | mips64vr5900el \ - | mipsisa32 | mipsisa32el \ - | mipsisa32r2 | mipsisa32r2el \ - | mipsisa32r6 | mipsisa32r6el \ - | mipsisa64 | mipsisa64el \ - | mipsisa64r2 | mipsisa64r2el \ - | mipsisa64r6 | mipsisa64r6el \ - | mipsisa64sb1 | mipsisa64sb1el \ - | mipsisa64sr71k | mipsisa64sr71kel \ - | mipsr5900 | mipsr5900el \ - | mipstx39 | mipstx39el \ - | mn10200 | mn10300 \ - | moxie \ - | mt \ - | msp430 \ - | nds32 | nds32le | nds32be \ - | nios | nios2 | nios2eb | nios2el \ - | ns16k | ns32k \ - | open8 | or1k | or1knd | or32 \ - | pdp10 | pdp11 | pj | pjl \ - | powerpc | powerpc64 | powerpc64le | powerpcle \ - | pru \ - | pyramid \ - | riscv32 | riscv64 \ - | rl78 | rx \ - | score \ - | sh | sh[1234] | sh[24]a | sh[24]aeb | sh[23]e | sh[234]eb | sheb | shbe | shle | sh[1234]le | sh3ele \ - | sh64 | sh64le \ - | sparc | sparc64 | sparc64b | sparc64v | sparc86x | sparclet | sparclite \ - | sparcv8 | sparcv9 | sparcv9b | sparcv9v \ - | spu \ - | tahoe | tic4x | tic54x | tic55x | tic6x | tic80 | tron \ - | ubicom32 \ - | v850 | v850e | v850e1 | v850e2 | v850es | v850e2v3 \ - | visium \ - | we32k \ - | x86 | xc16x | xstormy16 | xtensa \ - | z8k | z80) - basic_machine=$basic_machine-unknown - ;; - c54x) - basic_machine=tic54x-unknown - ;; - c55x) - basic_machine=tic55x-unknown - ;; - c6x) - basic_machine=tic6x-unknown - ;; - leon|leon[3-9]) - basic_machine=sparc-$basic_machine - ;; - m6811 | m68hc11 | m6812 | m68hc12 | m68hcs12x | nvptx | picochip) - basic_machine=$basic_machine-unknown - os=-none - ;; - m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k) - ;; - ms1) - basic_machine=mt-unknown - ;; - - strongarm | thumb | xscale) - basic_machine=arm-unknown - ;; - xgate) - basic_machine=$basic_machine-unknown - os=-none - ;; - xscaleeb) - basic_machine=armeb-unknown - ;; - - xscaleel) - basic_machine=armel-unknown - ;; - - # We use `pc' rather than `unknown' - # because (1) that's what they normally are, and - # (2) the word "unknown" tends to confuse beginning users. - i*86 | x86_64) - basic_machine=$basic_machine-pc - ;; - # Object if more than one company name word. - *-*-*) - echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 - exit 1 - ;; - # Recognize the basic CPU types with company name. - 580-* \ - | a29k-* \ - | aarch64-* | aarch64_be-* \ - | alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \ - | alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \ - | alphapca5[67]-* | alpha64pca5[67]-* | arc-* | arceb-* \ - | arm-* | armbe-* | armle-* | armeb-* | armv*-* \ - | avr-* | avr32-* \ - | ba-* \ - | be32-* | be64-* \ - | bfin-* | bs2000-* \ - | c[123]* | c30-* | [cjt]90-* | c4x-* \ - | c8051-* | clipper-* | craynv-* | cydra-* \ - | d10v-* | d30v-* | dlx-* \ - | e2k-* | elxsi-* \ - | f30[01]-* | f700-* | fido-* | fr30-* | frv-* | fx80-* \ - | h8300-* | h8500-* \ - | hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \ - | hexagon-* \ - | i*86-* | i860-* | i960-* | ia64-* \ - | ip2k-* | iq2000-* \ - | k1om-* \ - | le32-* | le64-* \ - | lm32-* \ - | m32c-* | m32r-* | m32rle-* \ - | m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \ - | m88110-* | m88k-* | maxq-* | mcore-* | metag-* \ - | microblaze-* | microblazeel-* \ - | mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \ - | mips16-* \ - | mips64-* | mips64el-* \ - | mips64octeon-* | mips64octeonel-* \ - | mips64orion-* | mips64orionel-* \ - | mips64r5900-* | mips64r5900el-* \ - | mips64vr-* | mips64vrel-* \ - | mips64vr4100-* | mips64vr4100el-* \ - | mips64vr4300-* | mips64vr4300el-* \ - | mips64vr5000-* | mips64vr5000el-* \ - | mips64vr5900-* | mips64vr5900el-* \ - | mipsisa32-* | mipsisa32el-* \ - | mipsisa32r2-* | mipsisa32r2el-* \ - | mipsisa32r6-* | mipsisa32r6el-* \ - | mipsisa64-* | mipsisa64el-* \ - | mipsisa64r2-* | mipsisa64r2el-* \ - | mipsisa64r6-* | mipsisa64r6el-* \ - | mipsisa64sb1-* | mipsisa64sb1el-* \ - | mipsisa64sr71k-* | mipsisa64sr71kel-* \ - | mipsr5900-* | mipsr5900el-* \ - | mipstx39-* | mipstx39el-* \ - | mmix-* \ - | mt-* \ - | msp430-* \ - | nds32-* | nds32le-* | nds32be-* \ - | nios-* | nios2-* | nios2eb-* | nios2el-* \ - | none-* | np1-* | ns16k-* | ns32k-* \ - | open8-* \ - | or1k*-* \ - | orion-* \ - | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \ - | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* \ - | pru-* \ - | pyramid-* \ - | riscv32-* | riscv64-* \ - | rl78-* | romp-* | rs6000-* | rx-* \ - | sh-* | sh[1234]-* | sh[24]a-* | sh[24]aeb-* | sh[23]e-* | sh[34]eb-* | sheb-* | shbe-* \ - | shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \ - | sparc-* | sparc64-* | sparc64b-* | sparc64v-* | sparc86x-* | sparclet-* \ - | sparclite-* \ - | sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | sv1-* | sx*-* \ - | tahoe-* \ - | tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \ - | tile*-* \ - | tron-* \ - | ubicom32-* \ - | v850-* | v850e-* | v850e1-* | v850es-* | v850e2-* | v850e2v3-* \ - | vax-* \ - | visium-* \ - | we32k-* \ - | x86-* | x86_64-* | xc16x-* | xps100-* \ - | xstormy16-* | xtensa*-* \ - | ymp-* \ - | z8k-* | z80-*) - ;; - # Recognize the basic CPU types without company name, with glob match. - xtensa*) - basic_machine=$basic_machine-unknown - ;; - # Recognize the various machine names and aliases which stand - # for a CPU type and a company and sometimes even an OS. - 386bsd) - basic_machine=i386-unknown - os=-bsd - ;; - 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc) - basic_machine=m68000-att - ;; - 3b*) - basic_machine=we32k-att - ;; - a29khif) - basic_machine=a29k-amd - os=-udi - ;; - abacus) - basic_machine=abacus-unknown - ;; - adobe68k) - basic_machine=m68010-adobe - os=-scout - ;; - alliant | fx80) - basic_machine=fx80-alliant - ;; - altos | altos3068) - basic_machine=m68k-altos - ;; - am29k) - basic_machine=a29k-none - os=-bsd - ;; - amd64) - basic_machine=x86_64-pc - ;; - amd64-*) - basic_machine=x86_64-`echo $basic_machine | sed 's/^[^-]*-//'` - ;; - amdahl) - basic_machine=580-amdahl - os=-sysv - ;; - amiga | amiga-*) - basic_machine=m68k-unknown - ;; - amigaos | amigados) - basic_machine=m68k-unknown - os=-amigaos - ;; - amigaunix | amix) - basic_machine=m68k-unknown - os=-sysv4 - ;; - apollo68) - basic_machine=m68k-apollo - os=-sysv - ;; - apollo68bsd) - basic_machine=m68k-apollo - os=-bsd - ;; - aros) - basic_machine=i386-pc - os=-aros - ;; - asmjs) - basic_machine=asmjs-unknown - ;; - aux) - basic_machine=m68k-apple - os=-aux - ;; - balance) - basic_machine=ns32k-sequent - os=-dynix - ;; - blackfin) - basic_machine=bfin-unknown - os=-linux - ;; - blackfin-*) - basic_machine=bfin-`echo $basic_machine | sed 's/^[^-]*-//'` - os=-linux - ;; - bluegene*) - basic_machine=powerpc-ibm - os=-cnk - ;; - c54x-*) - basic_machine=tic54x-`echo $basic_machine | sed 's/^[^-]*-//'` - ;; - c55x-*) - basic_machine=tic55x-`echo $basic_machine | sed 's/^[^-]*-//'` - ;; - c6x-*) - basic_machine=tic6x-`echo $basic_machine | sed 's/^[^-]*-//'` - ;; - c90) - basic_machine=c90-cray - os=-unicos - ;; - cegcc) - basic_machine=arm-unknown - os=-cegcc - ;; - convex-c1) - basic_machine=c1-convex - os=-bsd - ;; - convex-c2) - basic_machine=c2-convex - os=-bsd - ;; - convex-c32) - basic_machine=c32-convex - os=-bsd - ;; - convex-c34) - basic_machine=c34-convex - os=-bsd - ;; - convex-c38) - basic_machine=c38-convex - os=-bsd - ;; - cray | j90) - basic_machine=j90-cray - os=-unicos - ;; - craynv) - basic_machine=craynv-cray - os=-unicosmp - ;; - cr16 | cr16-*) - basic_machine=cr16-unknown - os=-elf - ;; - crds | unos) - basic_machine=m68k-crds - ;; - crisv32 | crisv32-* | etraxfs*) - basic_machine=crisv32-axis - ;; - cris | cris-* | etrax*) - basic_machine=cris-axis - ;; - crx) - basic_machine=crx-unknown - os=-elf - ;; - da30 | da30-*) - basic_machine=m68k-da30 - ;; - decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn) - basic_machine=mips-dec - ;; - decsystem10* | dec10*) - basic_machine=pdp10-dec - os=-tops10 - ;; - decsystem20* | dec20*) - basic_machine=pdp10-dec - os=-tops20 - ;; - delta | 3300 | motorola-3300 | motorola-delta \ - | 3300-motorola | delta-motorola) - basic_machine=m68k-motorola - ;; - delta88) - basic_machine=m88k-motorola - os=-sysv3 - ;; - dicos) - basic_machine=i686-pc - os=-dicos - ;; - djgpp) - basic_machine=i586-pc - os=-msdosdjgpp - ;; - dpx20 | dpx20-*) - basic_machine=rs6000-bull - os=-bosx - ;; - dpx2* | dpx2*-bull) - basic_machine=m68k-bull - 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) - basic_machine=a29k-amd - os=-ebmon - ;; - elxsi) - basic_machine=elxsi-elxsi - os=-bsd - ;; - encore | umax | mmax) - basic_machine=ns32k-encore - ;; - es1800 | OSE68k | ose68k | ose | OSE) - basic_machine=m68k-ericsson - os=-ose - ;; - fx2800) - basic_machine=i860-alliant - ;; - genix) - basic_machine=ns32k-ns - ;; - gmicro) - basic_machine=tron-gmicro - os=-sysv - ;; - go32) - basic_machine=i386-pc - os=-go32 - ;; - h3050r* | hiux*) - basic_machine=hppa1.1-hitachi - os=-hiuxwe2 - ;; - h8300hms) - basic_machine=h8300-hitachi - os=-hms - ;; - h8300xray) - basic_machine=h8300-hitachi - os=-xray - ;; - h8500hms) - basic_machine=h8500-hitachi - os=-hms - ;; - harris) - basic_machine=m88k-harris - os=-sysv3 - ;; - hp300-*) - basic_machine=m68k-hp - ;; - hp300bsd) - basic_machine=m68k-hp - os=-bsd - ;; - hp300hpux) - basic_machine=m68k-hp - os=-hpux - ;; - hp3k9[0-9][0-9] | hp9[0-9][0-9]) - basic_machine=hppa1.0-hp - ;; - hp9k2[0-9][0-9] | hp9k31[0-9]) - basic_machine=m68000-hp - ;; - hp9k3[2-9][0-9]) - basic_machine=m68k-hp - ;; - hp9k6[0-9][0-9] | hp6[0-9][0-9]) - basic_machine=hppa1.0-hp - ;; - hp9k7[0-79][0-9] | hp7[0-79][0-9]) - basic_machine=hppa1.1-hp - ;; - hp9k78[0-9] | hp78[0-9]) - # FIXME: really hppa2.0-hp - basic_machine=hppa1.1-hp - ;; - hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893) - # FIXME: really hppa2.0-hp - basic_machine=hppa1.1-hp - ;; - hp9k8[0-9][13679] | hp8[0-9][13679]) - basic_machine=hppa1.1-hp - ;; - hp9k8[0-9][0-9] | hp8[0-9][0-9]) - basic_machine=hppa1.0-hp - ;; - hppa-next) - os=-nextstep3 - ;; - hppaosf) - basic_machine=hppa1.1-hp - os=-osf - ;; - hppro) - basic_machine=hppa1.1-hp - os=-proelf - ;; - i370-ibm* | ibm*) - basic_machine=i370-ibm - ;; - i*86v32) - basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` - os=-sysv32 - ;; - i*86v4*) - basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` - os=-sysv4 - ;; - i*86v) - basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` - os=-sysv - ;; - i*86sol2) - basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` - os=-solaris2 - ;; - i386mach) - basic_machine=i386-mach - os=-mach - ;; - i386-vsta | vsta) - basic_machine=i386-unknown - os=-vsta - ;; - iris | iris4d) - basic_machine=mips-sgi - case $os in - -irix*) - ;; - *) - os=-irix4 - ;; - esac - ;; - isi68 | isi) - basic_machine=m68k-isi - os=-sysv - ;; - leon-*|leon[3-9]-*) - basic_machine=sparc-`echo $basic_machine | sed 's/-.*//'` - ;; - m68knommu) - basic_machine=m68k-unknown - os=-linux - ;; - m68knommu-*) - basic_machine=m68k-`echo $basic_machine | sed 's/^[^-]*-//'` - os=-linux - ;; - m88k-omron*) - basic_machine=m88k-omron - ;; - magnum | m3230) - basic_machine=mips-mips - os=-sysv - ;; - merlin) - basic_machine=ns32k-utek - os=-sysv - ;; - microblaze*) - basic_machine=microblaze-xilinx - ;; - mingw64) - basic_machine=x86_64-pc - os=-mingw64 - ;; - mingw32) - basic_machine=i686-pc - os=-mingw32 - ;; - mingw32ce) - basic_machine=arm-unknown - os=-mingw32ce - ;; - miniframe) - basic_machine=m68000-convergent - ;; - *mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*) - basic_machine=m68k-atari - os=-mint - ;; - mips3*-*) - basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'` - ;; - mips3*) - basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown - ;; - monitor) - basic_machine=m68k-rom68k - os=-coff - ;; - morphos) - basic_machine=powerpc-unknown - os=-morphos - ;; - moxiebox) - basic_machine=moxie-unknown - os=-moxiebox - ;; - msdos) - basic_machine=i386-pc - os=-msdos - ;; - ms1-*) - basic_machine=`echo $basic_machine | sed -e 's/ms1-/mt-/'` - ;; - msys) - basic_machine=i686-pc - os=-msys - ;; - mvs) - basic_machine=i370-ibm - os=-mvs - ;; - nacl) - basic_machine=le32-unknown - os=-nacl - ;; - ncr3000) - basic_machine=i486-ncr - os=-sysv4 - ;; - netbsd386) - basic_machine=i386-unknown - os=-netbsd - ;; - netwinder) - basic_machine=armv4l-rebel - os=-linux - ;; - news | news700 | news800 | news900) - basic_machine=m68k-sony - os=-newsos - ;; - news1000) - basic_machine=m68030-sony - os=-newsos - ;; - news-3600 | risc-news) - basic_machine=mips-sony - os=-newsos - ;; - necv70) - basic_machine=v70-nec - os=-sysv - ;; - next | m*-next ) - basic_machine=m68k-next - case $os in - -nextstep* ) - ;; - -ns2*) - os=-nextstep2 - ;; - *) - os=-nextstep3 - ;; - esac - ;; - nh3000) - basic_machine=m68k-harris - os=-cxux - ;; - nh[45]000) - basic_machine=m88k-harris - os=-cxux - ;; - nindy960) - basic_machine=i960-intel - os=-nindy - ;; - mon960) - basic_machine=i960-intel - os=-mon960 - ;; - nonstopux) - basic_machine=mips-compaq - os=-nonstopux - ;; - np1) - basic_machine=np1-gould - ;; - neo-tandem) - basic_machine=neo-tandem - ;; - nse-tandem) - basic_machine=nse-tandem - ;; - nsr-tandem) - basic_machine=nsr-tandem - ;; - op50n-* | op60c-*) - basic_machine=hppa1.1-oki - os=-proelf - ;; - openrisc | openrisc-*) - basic_machine=or32-unknown - ;; - os400) - basic_machine=powerpc-ibm - os=-os400 - ;; - OSE68000 | ose68000) - basic_machine=m68000-ericsson - os=-ose - ;; - os68k) - basic_machine=m68k-none - os=-os68k - ;; - pa-hitachi) - basic_machine=hppa1.1-hitachi - os=-hiuxwe2 - ;; - paragon) - basic_machine=i860-intel - os=-osf - ;; - parisc) - basic_machine=hppa-unknown - os=-linux - ;; - parisc-*) - basic_machine=hppa-`echo $basic_machine | sed 's/^[^-]*-//'` - os=-linux - ;; - pbd) - basic_machine=sparc-tti - ;; - pbb) - basic_machine=m68k-tti - ;; - pc532 | pc532-*) - basic_machine=ns32k-pc532 - ;; - pc98) - basic_machine=i386-pc - ;; - pc98-*) - basic_machine=i386-`echo $basic_machine | sed 's/^[^-]*-//'` - ;; - pentium | p5 | k5 | k6 | nexgen | viac3) - basic_machine=i586-pc - ;; - pentiumpro | p6 | 6x86 | athlon | athlon_*) - basic_machine=i686-pc - ;; - pentiumii | pentium2 | pentiumiii | pentium3) - basic_machine=i686-pc - ;; - pentium4) - basic_machine=i786-pc - ;; - pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*) - basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'` - ;; - pentiumpro-* | p6-* | 6x86-* | athlon-*) - basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` - ;; - pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*) - basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` - ;; - pentium4-*) - basic_machine=i786-`echo $basic_machine | sed 's/^[^-]*-//'` - ;; - pn) - basic_machine=pn-gould - ;; - power) basic_machine=power-ibm - ;; - ppc | ppcbe) basic_machine=powerpc-unknown - ;; - ppc-* | ppcbe-*) - basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'` - ;; - ppcle | powerpclittle) - basic_machine=powerpcle-unknown - ;; - ppcle-* | powerpclittle-*) - basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'` - ;; - ppc64) basic_machine=powerpc64-unknown - ;; - ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'` - ;; - ppc64le | powerpc64little) - basic_machine=powerpc64le-unknown - ;; - ppc64le-* | powerpc64little-*) - basic_machine=powerpc64le-`echo $basic_machine | sed 's/^[^-]*-//'` - ;; - ps2) - basic_machine=i386-ibm - ;; - pw32) - basic_machine=i586-unknown - os=-pw32 - ;; - rdos | rdos64) - basic_machine=x86_64-pc - os=-rdos - ;; - rdos32) - basic_machine=i386-pc - os=-rdos - ;; - rom68k) - basic_machine=m68k-rom68k - os=-coff - ;; - rm[46]00) - basic_machine=mips-siemens - ;; - rtpc | rtpc-*) - basic_machine=romp-ibm - ;; - s390 | s390-*) - basic_machine=s390-ibm - ;; - s390x | s390x-*) - basic_machine=s390x-ibm - ;; - sa29200) - basic_machine=a29k-amd - os=-udi - ;; - sb1) - basic_machine=mipsisa64sb1-unknown - ;; - sb1el) - basic_machine=mipsisa64sb1el-unknown - ;; - sde) - basic_machine=mipsisa32-sde - os=-elf - ;; - sei) - basic_machine=mips-sei - os=-seiux - ;; - sequent) - basic_machine=i386-sequent - ;; - sh) - basic_machine=sh-hitachi - os=-hms - ;; - sh5el) - basic_machine=sh5le-unknown - ;; - sh64) - basic_machine=sh64-unknown - ;; - sparclite-wrs | simso-wrs) - basic_machine=sparclite-wrs - os=-vxworks - ;; - sps7) - basic_machine=m68k-bull - os=-sysv2 - ;; - spur) - basic_machine=spur-unknown - ;; - st2000) - basic_machine=m68k-tandem - ;; - stratus) - basic_machine=i860-stratus - os=-sysv4 - ;; - strongarm-* | thumb-*) - basic_machine=arm-`echo $basic_machine | sed 's/^[^-]*-//'` - ;; - sun2) - basic_machine=m68000-sun - ;; - sun2os3) - basic_machine=m68000-sun - os=-sunos3 - ;; - sun2os4) - basic_machine=m68000-sun - os=-sunos4 - ;; - sun3os3) - basic_machine=m68k-sun - os=-sunos3 - ;; - sun3os4) - basic_machine=m68k-sun - os=-sunos4 - ;; - sun4os3) - basic_machine=sparc-sun - os=-sunos3 - ;; - sun4os4) - basic_machine=sparc-sun - os=-sunos4 - ;; - sun4sol2) - basic_machine=sparc-sun - os=-solaris2 - ;; - sun3 | sun3-*) - basic_machine=m68k-sun - ;; - sun4) - basic_machine=sparc-sun - ;; - sun386 | sun386i | roadrunner) - basic_machine=i386-sun - ;; - sv1) - basic_machine=sv1-cray - os=-unicos - ;; - symmetry) - basic_machine=i386-sequent - os=-dynix - ;; - t3e) - basic_machine=alphaev5-cray - os=-unicos - ;; - t90) - basic_machine=t90-cray - os=-unicos - ;; - tile*) - basic_machine=$basic_machine-unknown - os=-linux-gnu - ;; - tx39) - basic_machine=mipstx39-unknown - ;; - tx39el) - basic_machine=mipstx39el-unknown - ;; - toad1) - basic_machine=pdp10-xkl - os=-tops20 - ;; - tower | tower-32) - basic_machine=m68k-ncr - ;; - tpf) - basic_machine=s390x-ibm - os=-tpf - ;; - udi29k) - basic_machine=a29k-amd - os=-udi - ;; - ultra3) - basic_machine=a29k-nyu - os=-sym1 - ;; - v810 | necv810) - basic_machine=v810-nec - os=-none - ;; - vaxv) - basic_machine=vax-dec - os=-sysv - ;; - vms) - basic_machine=vax-dec - os=-vms - ;; - vpp*|vx|vx-*) - basic_machine=f301-fujitsu - ;; - vxworks960) - basic_machine=i960-wrs - os=-vxworks - ;; - vxworks68) - basic_machine=m68k-wrs - os=-vxworks - ;; - vxworks29k) - basic_machine=a29k-wrs - os=-vxworks - ;; - w65*) - basic_machine=w65-wdc - os=-none - ;; - w89k-*) - basic_machine=hppa1.1-winbond - os=-proelf - ;; - xbox) - basic_machine=i686-pc - os=-mingw32 - ;; - xps | xps100) - basic_machine=xps100-honeywell - ;; - xscale-* | xscalee[bl]-*) - basic_machine=`echo $basic_machine | sed 's/^xscale/arm/'` - ;; - ymp) - basic_machine=ymp-cray - os=-unicos - ;; - z8k-*-coff) - basic_machine=z8k-unknown - os=-sim - ;; - z80-*-coff) - basic_machine=z80-unknown - os=-sim - ;; - none) - basic_machine=none-none - os=-none - ;; - -# Here we handle the default manufacturer of certain CPU types. It is in -# some cases the only manufacturer, in others, it is the most popular. - w89k) - basic_machine=hppa1.1-winbond - ;; - op50n) - basic_machine=hppa1.1-oki - ;; - op60c) - basic_machine=hppa1.1-oki - ;; - romp) - basic_machine=romp-ibm - ;; - mmix) - basic_machine=mmix-knuth - ;; - rs6000) - basic_machine=rs6000-ibm - ;; - vax) - basic_machine=vax-dec - ;; - pdp10) - # there are many clones, so DEC is not a safe bet - basic_machine=pdp10-unknown - ;; - pdp11) - basic_machine=pdp11-dec - ;; - we32k) - basic_machine=we32k-att - ;; - sh[1234] | sh[24]a | sh[24]aeb | sh[34]eb | sh[1234]le | sh[23]ele) - basic_machine=sh-unknown - ;; - sparc | sparcv8 | sparcv9 | sparcv9b | sparcv9v) - basic_machine=sparc-sun - ;; - cydra) - basic_machine=cydra-cydrome - ;; - orion) - basic_machine=orion-highlevel - ;; - orion105) - basic_machine=clipper-highlevel - ;; - mac | mpw | mac-mpw) - basic_machine=m68k-apple - ;; - pmac | pmac-mpw) - basic_machine=powerpc-apple - ;; - *-unknown) - # Make sure to match an already-canonicalized machine name. - ;; - *) - echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 - exit 1 - ;; -esac - -# Here we canonicalize certain aliases for manufacturers. -case $basic_machine in - *-digital*) - basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'` - ;; - *-commodore*) - basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'` - ;; - *) - ;; -esac - -# Decode manufacturer-specific aliases for certain operating systems. - -if [ x"$os" != x"" ] -then -case $os in - # First match some system type aliases - # that might get confused with valid system types. - # -solaris* is a basic system type, with this one exception. - -auroraux) - os=-auroraux - ;; - -solaris1 | -solaris1.*) - os=`echo $os | sed -e 's|solaris1|sunos4|'` - ;; - -solaris) - os=-solaris2 - ;; - -svr4*) - os=-sysv4 - ;; - -unixware*) - os=-sysv4.2uw - ;; - -gnu/linux*) - os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'` - ;; - # First accept the basic system types. - # The portable systems comes first. - # Each alternative MUST END IN A *, to match a version number. - # -sysv* is not here because it comes later, after sysvr4. - -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \ - | -*vms* | -sco* | -esix* | -isc* | -aix* | -cnk* | -sunos | -sunos[34]*\ - | -hpux* | -unos* | -osf* | -luna* | -dgux* | -auroraux* | -solaris* \ - | -sym* | -kopensolaris* | -plan9* \ - | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \ - | -aos* | -aros* | -cloudabi* | -sortix* \ - | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \ - | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \ - | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \ - | -bitrig* | -openbsd* | -solidbsd* | -libertybsd* \ - | -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \ - | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \ - | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \ - | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \ - | -chorusos* | -chorusrdb* | -cegcc* \ - | -cygwin* | -msys* | -pe* | -psos* | -moss* | -proelf* | -rtems* \ - | -midipix* | -mingw32* | -mingw64* | -linux-gnu* | -linux-android* \ - | -linux-newlib* | -linux-musl* | -linux-uclibc* \ - | -uxpv* | -beos* | -mpeix* | -udk* | -moxiebox* \ - | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \ - | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \ - | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \ - | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \ - | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \ - | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \ - | -skyos* | -haiku* | -rdos* | -toppers* | -drops* | -es* \ - | -onefs* | -tirtos* | -phoenix* | -fuchsia*) - # Remember, each alternative MUST END IN *, to match a version number. - ;; - -qnx*) - case $basic_machine in - x86-* | i*86-*) - ;; - *) - os=-nto$os - ;; - esac - ;; - -nto-qnx*) - ;; - -nto*) - os=`echo $os | sed -e 's|nto|nto-qnx|'` - ;; - -sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \ - | -windows* | -osx | -abug | -netware* | -os9* | -beos* | -haiku* \ - | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*) - ;; - -mac*) - os=`echo $os | sed -e 's|mac|macos|'` - ;; - -linux-dietlibc) - os=-linux-dietlibc - ;; - -linux*) - os=`echo $os | sed -e 's|linux|linux-gnu|'` - ;; - -sunos5*) - os=`echo $os | sed -e 's|sunos5|solaris2|'` - ;; - -sunos6*) - os=`echo $os | sed -e 's|sunos6|solaris3|'` - ;; - -opened*) - os=-openedition - ;; - -os400*) - os=-os400 - ;; - -wince*) - os=-wince - ;; - -osfrose*) - os=-osfrose - ;; - -osf*) - os=-osf - ;; - -utek*) - os=-bsd - ;; - -dynix*) - os=-bsd - ;; - -acis*) - os=-aos - ;; - -atheos*) - os=-atheos - ;; - -syllable*) - os=-syllable - ;; - -386bsd) - os=-bsd - ;; - -ctix* | -uts*) - os=-sysv - ;; - -nova*) - os=-rtmk-nova - ;; - -ns2 ) - os=-nextstep2 - ;; - -nsk*) - os=-nsk - ;; - # Preserve the version number of sinix5. - -sinix5.*) - os=`echo $os | sed -e 's|sinix|sysv|'` - ;; - -sinix*) - os=-sysv4 - ;; - -tpf*) - os=-tpf - ;; - -triton*) - os=-sysv3 - ;; - -oss*) - os=-sysv3 - ;; - -svr4) - os=-sysv4 - ;; - -svr3) - os=-sysv3 - ;; - -sysvr4) - os=-sysv4 - ;; - # This must come after -sysvr4. - -sysv*) - ;; - -ose*) - os=-ose - ;; - -es1800*) - os=-ose - ;; - -xenix) - os=-xenix - ;; - -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) - os=-mint - ;; - -aros*) - os=-aros - ;; - -zvmoe) - os=-zvmoe - ;; - -dicos*) - os=-dicos - ;; - -nacl*) - ;; - -ios) - ;; - -none) - ;; - *) - # Get rid of the `-' at the beginning of $os. - os=`echo $os | sed 's/[^-]*-//'` - echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2 - exit 1 - ;; -esac -else - -# Here we handle the default operating systems that come with various machines. -# The value should be what the vendor currently ships out the door with their -# machine or put another way, the most popular os provided with the machine. - -# Note that if you're going to try to match "-MANUFACTURER" here (say, -# "-sun"), then you have to tell the case statement up towards the top -# that MANUFACTURER isn't an operating system. Otherwise, code above -# will signal an error saying that MANUFACTURER isn't an operating -# system, and we'll never get to this point. - -case $basic_machine in - score-*) - os=-elf - ;; - spu-*) - os=-elf - ;; - *-acorn) - os=-riscix1.2 - ;; - arm*-rebel) - os=-linux - ;; - arm*-semi) - os=-aout - ;; - c4x-* | tic4x-*) - os=-coff - ;; - c8051-*) - os=-elf - ;; - hexagon-*) - os=-elf - ;; - tic54x-*) - os=-coff - ;; - tic55x-*) - os=-coff - ;; - tic6x-*) - os=-coff - ;; - # This must come before the *-dec entry. - pdp10-*) - os=-tops20 - ;; - pdp11-*) - os=-none - ;; - *-dec | vax-*) - os=-ultrix4.2 - ;; - m68*-apollo) - os=-domain - ;; - i386-sun) - os=-sunos4.0.2 - ;; - m68000-sun) - os=-sunos3 - ;; - m68*-cisco) - os=-aout - ;; - mep-*) - os=-elf - ;; - mips*-cisco) - os=-elf - ;; - mips*-*) - os=-elf - ;; - or32-*) - os=-coff - ;; - *-tti) # must be before sparc entry or we get the wrong os. - os=-sysv3 - ;; - sparc-* | *-sun) - os=-sunos4.1.1 - ;; - *-be) - os=-beos - ;; - *-haiku) - os=-haiku - ;; - *-ibm) - os=-aix - ;; - *-knuth) - os=-mmixware - ;; - *-wec) - os=-proelf - ;; - *-winbond) - os=-proelf - ;; - *-oki) - os=-proelf - ;; - *-hp) - os=-hpux - ;; - *-hitachi) - os=-hiux - ;; - i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent) - os=-sysv - ;; - *-cbm) - os=-amigaos - ;; - *-dg) - os=-dgux - ;; - *-dolphin) - os=-sysv3 - ;; - m68k-ccur) - os=-rtu - ;; - m88k-omron*) - os=-luna - ;; - *-next ) - os=-nextstep - ;; - *-sequent) - os=-ptx - ;; - *-crds) - os=-unos - ;; - *-ns) - os=-genix - ;; - i370-*) - os=-mvs - ;; - *-next) - os=-nextstep3 - ;; - *-gould) - os=-sysv - ;; - *-highlevel) - os=-bsd - ;; - *-encore) - os=-bsd - ;; - *-sgi) - os=-irix - ;; - *-siemens) - os=-sysv4 - ;; - *-masscomp) - os=-rtu - ;; - f30[01]-fujitsu | f700-fujitsu) - os=-uxpv - ;; - *-rom68k) - os=-coff - ;; - *-*bug) - os=-coff - ;; - *-apple) - os=-macos - ;; - *-atari*) - os=-mint - ;; - *) - os=-none - ;; -esac -fi - -# Here we handle the case where we know the os, and the CPU type, but not the -# manufacturer. We pick the logical manufacturer. -vendor=unknown -case $basic_machine in - *-unknown) - case $os in - -riscix*) - vendor=acorn - ;; - -sunos*) - vendor=sun - ;; - -cnk*|-aix*) - vendor=ibm - ;; - -beos*) - vendor=be - ;; - -hpux*) - vendor=hp - ;; - -mpeix*) - vendor=hp - ;; - -hiux*) - vendor=hitachi - ;; - -unos*) - vendor=crds - ;; - -dgux*) - vendor=dg - ;; - -luna*) - vendor=omron - ;; - -genix*) - vendor=ns - ;; - -mvs* | -opened*) - vendor=ibm - ;; - -os400*) - vendor=ibm - ;; - -ptx*) - vendor=sequent - ;; - -tpf*) - vendor=ibm - ;; - -vxsim* | -vxworks* | -windiss*) - vendor=wrs - ;; - -aux*) - vendor=apple - ;; - -hms*) - vendor=hitachi - ;; - -mpw* | -macos*) - vendor=apple - ;; - -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) - vendor=atari - ;; - -vos*) - vendor=stratus - ;; - esac - basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"` - ;; -esac - -echo $basic_machine$os -exit - -# Local variables: -# eval: (add-hook 'write-file-hooks 'time-stamp) -# time-stamp-start: "timestamp='" -# time-stamp-format: "%:y-%02m-%02d" -# time-stamp-end: "'" -# End: ->>>>>>> main diff --git a/contrib/jemalloc/configure.ac b/contrib/jemalloc/configure.ac index f7285a6154b9..f6d25f3345ee 100644 --- a/contrib/jemalloc/configure.ac +++ b/contrib/jemalloc/configure.ac @@ -1,4 +1,3 @@ -<<<<<<< HEAD dnl Process this file with autoconf to produce a configure script. AC_PREREQ(2.68) AC_INIT([Makefile.in]) @@ -2668,2412 +2667,3 @@ AC_MSG_RESULT([lazy_lock : ${enable_lazy_lock}]) AC_MSG_RESULT([cache-oblivious : ${enable_cache_oblivious}]) AC_MSG_RESULT([cxx : ${enable_cxx}]) AC_MSG_RESULT([===============================================================================]) -||||||| dec341af7695 -======= -dnl Process this file with autoconf to produce a configure script. -AC_PREREQ(2.68) -AC_INIT([Makefile.in]) - -AC_CONFIG_AUX_DIR([build-aux]) - -dnl ============================================================================ -dnl Custom macro definitions. - -dnl JE_CONCAT_VVV(r, a, b) -dnl -dnl Set $r to the concatenation of $a and $b, with a space separating them iff -dnl both $a and $b are non-empty. -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]) -T_CONFIGURE_CFLAGS="${CONFIGURE_CFLAGS}" -JE_APPEND_VS(CONFIGURE_CFLAGS, $1) -JE_CONCAT_VVV(CFLAGS, CONFIGURE_CFLAGS, SPECIFIED_CFLAGS) -AC_COMPILE_IFELSE([AC_LANG_PROGRAM( -[[ -]], [[ - return 0; -]])], - [je_cv_cflags_added=$1] - AC_MSG_RESULT([yes]), - [je_cv_cflags_added=] - AC_MSG_RESULT([no]) - [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) -) - -CONFIGURE_CXXFLAGS= -SPECIFIED_CXXFLAGS="${CXXFLAGS}" -dnl JE_CXXFLAGS_ADD(cxxflag) -AC_DEFUN([JE_CXXFLAGS_ADD], -[ -AC_MSG_CHECKING([whether compiler supports $1]) -T_CONFIGURE_CXXFLAGS="${CONFIGURE_CXXFLAGS}" -JE_APPEND_VS(CONFIGURE_CXXFLAGS, $1) -JE_CONCAT_VVV(CXXFLAGS, CONFIGURE_CXXFLAGS, SPECIFIED_CXXFLAGS) -AC_LANG_PUSH([C++]) -AC_COMPILE_IFELSE([AC_LANG_PROGRAM( -[[ -]], [[ - return 0; -]])], - [je_cv_cxxflags_added=$1] - AC_MSG_RESULT([yes]), - [je_cv_cxxflags_added=] - AC_MSG_RESULT([no]) - [CONFIGURE_CXXFLAGS="${T_CONFIGURE_CXXFLAGS}"] -) -AC_LANG_POP([C++]) -JE_CONCAT_VVV(CXXFLAGS, CONFIGURE_CXXFLAGS, SPECIFIED_CXXFLAGS) -]) - -dnl JE_COMPILABLE(label, hcode, mcode, rvar) -dnl -dnl Use AC_LINK_IFELSE() rather than AC_COMPILE_IFELSE() so that linker errors -dnl cause failure. -AC_DEFUN([JE_COMPILABLE], -[ -AC_CACHE_CHECK([whether $1 is compilable], - [$4], - [AC_LINK_IFELSE([AC_LANG_PROGRAM([$2], - [$3])], - [$4=yes], - [$4=no])]) -]) - -dnl ============================================================================ - -CONFIG=`echo ${ac_configure_args} | sed -e 's#'"'"'\([^ ]*\)'"'"'#\1#g'` -AC_SUBST([CONFIG]) - -dnl Library revision. -rev=2 -AC_SUBST([rev]) - -srcroot=$srcdir -if test "x${srcroot}" = "x." ; then - srcroot="" -else - srcroot="${srcroot}/" -fi -AC_SUBST([srcroot]) -abs_srcroot="`cd \"${srcdir}\"; pwd`/" -AC_SUBST([abs_srcroot]) - -objroot="" -AC_SUBST([objroot]) -abs_objroot="`pwd`/" -AC_SUBST([abs_objroot]) - -dnl Munge install path variables. -if test "x$prefix" = "xNONE" ; then - prefix="/usr/local" -fi -if test "x$exec_prefix" = "xNONE" ; then - exec_prefix=$prefix -fi -PREFIX=$prefix -AC_SUBST([PREFIX]) -BINDIR=`eval echo $bindir` -BINDIR=`eval echo $BINDIR` -AC_SUBST([BINDIR]) -INCLUDEDIR=`eval echo $includedir` -INCLUDEDIR=`eval echo $INCLUDEDIR` -AC_SUBST([INCLUDEDIR]) -LIBDIR=`eval echo $libdir` -LIBDIR=`eval echo $LIBDIR` -AC_SUBST([LIBDIR]) -DATADIR=`eval echo $datadir` -DATADIR=`eval echo $DATADIR` -AC_SUBST([DATADIR]) -MANDIR=`eval echo $mandir` -MANDIR=`eval echo $MANDIR` -AC_SUBST([MANDIR]) - -dnl Support for building documentation. -AC_PATH_PROG([XSLTPROC], [xsltproc], [false], [$PATH]) -if test -d "/usr/share/xml/docbook/stylesheet/docbook-xsl" ; then - DEFAULT_XSLROOT="/usr/share/xml/docbook/stylesheet/docbook-xsl" -elif test -d "/usr/share/sgml/docbook/xsl-stylesheets" ; then - DEFAULT_XSLROOT="/usr/share/sgml/docbook/xsl-stylesheets" -else - dnl Documentation building will fail if this default gets used. - DEFAULT_XSLROOT="" -fi -AC_ARG_WITH([xslroot], - [AS_HELP_STRING([--with-xslroot=<path>], [XSL stylesheet root path])], [ -if test "x$with_xslroot" = "xno" ; then - XSLROOT="${DEFAULT_XSLROOT}" -else - XSLROOT="${with_xslroot}" -fi -], - XSLROOT="${DEFAULT_XSLROOT}" -) -if test "x$XSLTPROC" = "xfalse" ; then - XSLROOT="" -fi -AC_SUBST([XSLROOT]) - -dnl If CFLAGS isn't defined, set CFLAGS to something reasonable. Otherwise, -dnl just prevent autoconf from molesting CFLAGS. -CFLAGS=$CFLAGS -AC_PROG_CC - -if test "x$GCC" != "xyes" ; then - AC_CACHE_CHECK([whether compiler is MSVC], - [je_cv_msvc], - [AC_COMPILE_IFELSE([AC_LANG_PROGRAM([], - [ -#ifndef _MSC_VER - int fail[-1]; -#endif -])], - [je_cv_msvc=yes], - [je_cv_msvc=no])]) -fi - -dnl check if a cray prgenv wrapper compiler is being used -je_cv_cray_prgenv_wrapper="" -if test "x${PE_ENV}" != "x" ; then - case "${CC}" in - 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]) - fi - fi - JE_CFLAGS_ADD([-Wall]) - JE_CFLAGS_ADD([-Wextra]) - JE_CFLAGS_ADD([-Wshorten-64-to-32]) - JE_CFLAGS_ADD([-Wsign-compare]) - JE_CFLAGS_ADD([-Wundef]) - JE_CFLAGS_ADD([-Wno-format-zero-length]) - JE_CFLAGS_ADD([-pipe]) - JE_CFLAGS_ADD([-g3]) -elif test "x$je_cv_msvc" = "xyes" ; then - CC="$CC -nologo" - JE_CFLAGS_ADD([-Zi]) - JE_CFLAGS_ADD([-MT]) - JE_CFLAGS_ADD([-W3]) - 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 - dnl ignore unreachable code warning - JE_CFLAGS_ADD([-hnomessage=128]) - dnl ignore redefinition of "malloc", "free", etc warning - JE_CFLAGS_ADD([-hnomessage=1357]) -fi -AC_SUBST([CONFIGURE_CFLAGS]) -AC_SUBST([SPECIFIED_CFLAGS]) -AC_SUBST([EXTRA_CFLAGS]) -AC_PROG_CPP - -AC_ARG_ENABLE([cxx], - [AS_HELP_STRING([--disable-cxx], [Disable C++ integration])], -if test "x$enable_cxx" = "xno" ; then - enable_cxx="0" -else - enable_cxx="1" -fi -, -enable_cxx="1" -) -if test "x$enable_cxx" = "x1" ; then - dnl Require at least c++14, which is the first version to support sized - dnl deallocation. C++ support is not compiled otherwise. - m4_include([m4/ax_cxx_compile_stdcxx.m4]) - AX_CXX_COMPILE_STDCXX([14], [noext], [optional]) - if test "x${HAVE_CXX14}" = "x1" ; then - JE_CXXFLAGS_ADD([-Wall]) - JE_CXXFLAGS_ADD([-Wextra]) - JE_CXXFLAGS_ADD([-g3]) - - SAVED_LIBS="${LIBS}" - JE_APPEND_VS(LIBS, -lstdc++) - JE_COMPILABLE([libstdc++ linkage], [ -#include <stdlib.h> -], [[ - int *arr = (int *)malloc(sizeof(int) * 42); - if (arr == NULL) - return 1; -]], [je_cv_libstdcxx]) - if test "x${je_cv_libstdcxx}" = "xno" ; then - LIBS="${SAVED_LIBS}" - fi - else - enable_cxx="0" - fi -fi -AC_SUBST([enable_cxx]) -AC_SUBST([CONFIGURE_CXXFLAGS]) -AC_SUBST([SPECIFIED_CXXFLAGS]) -AC_SUBST([EXTRA_CXXFLAGS]) - -AC_C_BIGENDIAN([ac_cv_big_endian=1], [ac_cv_big_endian=0]) -if test "x${ac_cv_big_endian}" = "x1" ; then - AC_DEFINE_UNQUOTED([JEMALLOC_BIG_ENDIAN], [ ]) -fi - -if test "x${je_cv_msvc}" = "xyes" -a "x${ac_cv_header_inttypes_h}" = "xno"; then - JE_APPEND_VS(CPPFLAGS, -I${srcdir}/include/msvc_compat/C99) -fi - -if test "x${je_cv_msvc}" = "xyes" ; then - LG_SIZEOF_PTR=LG_SIZEOF_PTR_WIN - AC_MSG_RESULT([Using a predefined value for sizeof(void *): 4 for 32-bit, 8 for 64-bit]) -else - AC_CHECK_SIZEOF([void *]) - if test "x${ac_cv_sizeof_void_p}" = "x8" ; then - LG_SIZEOF_PTR=3 - elif test "x${ac_cv_sizeof_void_p}" = "x4" ; then - LG_SIZEOF_PTR=2 - else - AC_MSG_ERROR([Unsupported pointer size: ${ac_cv_sizeof_void_p}]) - fi -fi -AC_DEFINE_UNQUOTED([LG_SIZEOF_PTR], [$LG_SIZEOF_PTR]) - -AC_CHECK_SIZEOF([int]) -if test "x${ac_cv_sizeof_int}" = "x8" ; then - LG_SIZEOF_INT=3 -elif test "x${ac_cv_sizeof_int}" = "x4" ; then - LG_SIZEOF_INT=2 -else - AC_MSG_ERROR([Unsupported int size: ${ac_cv_sizeof_int}]) -fi -AC_DEFINE_UNQUOTED([LG_SIZEOF_INT], [$LG_SIZEOF_INT]) - -AC_CHECK_SIZEOF([long]) -if test "x${ac_cv_sizeof_long}" = "x8" ; then - LG_SIZEOF_LONG=3 -elif test "x${ac_cv_sizeof_long}" = "x4" ; then - LG_SIZEOF_LONG=2 -else - AC_MSG_ERROR([Unsupported long size: ${ac_cv_sizeof_long}]) -fi -AC_DEFINE_UNQUOTED([LG_SIZEOF_LONG], [$LG_SIZEOF_LONG]) - -AC_CHECK_SIZEOF([long long]) -if test "x${ac_cv_sizeof_long_long}" = "x8" ; then - LG_SIZEOF_LONG_LONG=3 -elif test "x${ac_cv_sizeof_long_long}" = "x4" ; then - LG_SIZEOF_LONG_LONG=2 -else - AC_MSG_ERROR([Unsupported long long size: ${ac_cv_sizeof_long_long}]) -fi -AC_DEFINE_UNQUOTED([LG_SIZEOF_LONG_LONG], [$LG_SIZEOF_LONG_LONG]) - -AC_CHECK_SIZEOF([intmax_t]) -if test "x${ac_cv_sizeof_intmax_t}" = "x16" ; then - LG_SIZEOF_INTMAX_T=4 -elif test "x${ac_cv_sizeof_intmax_t}" = "x8" ; then - LG_SIZEOF_INTMAX_T=3 -elif test "x${ac_cv_sizeof_intmax_t}" = "x4" ; then - LG_SIZEOF_INTMAX_T=2 -else - AC_MSG_ERROR([Unsupported intmax_t size: ${ac_cv_sizeof_intmax_t}]) -fi -AC_DEFINE_UNQUOTED([LG_SIZEOF_INTMAX_T], [$LG_SIZEOF_INTMAX_T]) - -AC_CANONICAL_HOST -dnl CPU-specific settings. -CPU_SPINWAIT="" -case "${host_cpu}" in - i686|x86_64) - HAVE_CPU_SPINWAIT=1 - if test "x${je_cv_msvc}" = "xyes" ; then - AC_CACHE_VAL([je_cv_pause_msvc], - [JE_COMPILABLE([pause instruction MSVC], [], - [[_mm_pause(); return 0;]], - [je_cv_pause_msvc])]) - if test "x${je_cv_pause_msvc}" = "xyes" ; then - CPU_SPINWAIT='_mm_pause()' - fi - else - AC_CACHE_VAL([je_cv_pause], - [JE_COMPILABLE([pause instruction], [], - [[__asm__ volatile("pause"); return 0;]], - [je_cv_pause])]) - if test "x${je_cv_pause}" = "xyes" ; then - CPU_SPINWAIT='__asm__ volatile("pause")' - fi - fi - ;; - *) - HAVE_CPU_SPINWAIT=0 - ;; -esac -AC_DEFINE_UNQUOTED([HAVE_CPU_SPINWAIT], [$HAVE_CPU_SPINWAIT]) -AC_DEFINE_UNQUOTED([CPU_SPINWAIT], [$CPU_SPINWAIT]) - -AC_ARG_WITH([lg_vaddr], - [AS_HELP_STRING([--with-lg-vaddr=<lg-vaddr>], [Number of significant virtual address bits])], - [LG_VADDR="$with_lg_vaddr"], [LG_VADDR="detect"]) - -case "${host_cpu}" in - aarch64) - if test "x$LG_VADDR" = "xdetect"; then - AC_MSG_CHECKING([number of significant virtual address bits]) - if test "x${LG_SIZEOF_PTR}" = "x2" ; then - #aarch64 ILP32 - LG_VADDR=32 - else - #aarch64 LP64 - LG_VADDR=48 - fi - AC_MSG_RESULT([$LG_VADDR]) - fi - ;; - x86_64) - if test "x$LG_VADDR" = "xdetect"; then - AC_CACHE_CHECK([number of significant virtual address bits], - [je_cv_lg_vaddr], - AC_RUN_IFELSE([AC_LANG_PROGRAM( -[[ -#include <stdio.h> -#ifdef _WIN32 -#include <limits.h> -#include <intrin.h> -typedef unsigned __int32 uint32_t; -#else -#include <stdint.h> -#endif -]], [[ - uint32_t r[[4]]; - uint32_t eax_in = 0x80000008U; -#ifdef _WIN32 - __cpuid((int *)r, (int)eax_in); -#else - asm volatile ("cpuid" - : "=a" (r[[0]]), "=b" (r[[1]]), "=c" (r[[2]]), "=d" (r[[3]]) - : "a" (eax_in), "c" (0) - ); -#endif - uint32_t eax_out = r[[0]]; - uint32_t vaddr = ((eax_out & 0x0000ff00U) >> 8); - FILE *f = fopen("conftest.out", "w"); - if (f == NULL) { - return 1; - } - if (vaddr > (sizeof(void *) << 3)) { - vaddr = sizeof(void *) << 3; - } - fprintf(f, "%u", vaddr); - fclose(f); - return 0; -]])], - [je_cv_lg_vaddr=`cat conftest.out`], - [je_cv_lg_vaddr=error], - [je_cv_lg_vaddr=57])) - if test "x${je_cv_lg_vaddr}" != "x" ; then - LG_VADDR="${je_cv_lg_vaddr}" - fi - if test "x${LG_VADDR}" != "xerror" ; then - AC_DEFINE_UNQUOTED([LG_VADDR], [$LG_VADDR]) - else - AC_MSG_ERROR([cannot determine number of significant virtual address bits]) - fi - fi - ;; - *) - if test "x$LG_VADDR" = "xdetect"; then - AC_MSG_CHECKING([number of significant virtual address bits]) - if test "x${LG_SIZEOF_PTR}" = "x3" ; then - LG_VADDR=64 - elif test "x${LG_SIZEOF_PTR}" = "x2" ; then - LG_VADDR=32 - elif test "x${LG_SIZEOF_PTR}" = "xLG_SIZEOF_PTR_WIN" ; then - LG_VADDR="(1U << (LG_SIZEOF_PTR_WIN+3))" - else - AC_MSG_ERROR([Unsupported lg(pointer size): ${LG_SIZEOF_PTR}]) - fi - AC_MSG_RESULT([$LG_VADDR]) - fi - ;; -esac -AC_DEFINE_UNQUOTED([LG_VADDR], [$LG_VADDR]) - -LD_PRELOAD_VAR="LD_PRELOAD" -so="so" -importlib="${so}" -o="$ac_objext" -a="a" -exe="$ac_exeext" -libprefix="lib" -link_whole_archive="0" -DSO_LDFLAGS='-shared -Wl,-soname,$(@F)' -RPATH='-Wl,-rpath,$(1)' -SOREV="${so}.${rev}" -PIC_CFLAGS='-fPIC -DPIC' -CTARGET='-o $@' -LDTARGET='-o $@' -TEST_LD_MODE= -EXTRA_LDFLAGS= -ARFLAGS='crus' -AROUT=' $@' -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_PROGRAM([ar], [AC_PROG_AR]) -AC_DEFUN([AC_PROG_AR], [AC_CHECK_TOOL(AR, ar, :)]) -AC_PROG_AR - -AN_MAKEVAR([NM], [AC_PROG_NM]) -AN_PROGRAM([nm], [AC_PROG_NM]) -AC_DEFUN([AC_PROG_NM], [AC_CHECK_TOOL(NM, nm, :)]) -AC_PROG_NM - -AC_PROG_AWK - -dnl ============================================================================ -dnl jemalloc version. -dnl - -AC_ARG_WITH([version], - [AS_HELP_STRING([--with-version=<major>.<minor>.<bugfix>-<nrev>-g<gid>], - [Version string])], - [ - echo "${with_version}" | grep ['^[0-9]\+\.[0-9]\+\.[0-9]\+-[0-9]\+-g[0-9a-f]\+$'] 2>&1 1>/dev/null - if test $? -eq 0 ; then - echo "$with_version" > "${objroot}VERSION" - else - echo "${with_version}" | grep ['^VERSION$'] 2>&1 1>/dev/null - if test $? -ne 0 ; then - AC_MSG_ERROR([${with_version} does not match <major>.<minor>.<bugfix>-<nrev>-g<gid> or VERSION]) - fi - fi - ], [ - dnl Set VERSION if source directory is inside a git repository. - if test "x`test ! \"${srcroot}\" && cd \"${srcroot}\"; git rev-parse --is-inside-work-tree 2>/dev/null`" = "xtrue" ; then - dnl Pattern globs aren't powerful enough to match both single- and - dnl double-digit version numbers, so iterate over patterns to support up - dnl to version 99.99.99 without any accidental matches. - for pattern in ['[0-9].[0-9].[0-9]' '[0-9].[0-9].[0-9][0-9]' \ - '[0-9].[0-9][0-9].[0-9]' '[0-9].[0-9][0-9].[0-9][0-9]' \ - '[0-9][0-9].[0-9].[0-9]' '[0-9][0-9].[0-9].[0-9][0-9]' \ - '[0-9][0-9].[0-9][0-9].[0-9]' \ - '[0-9][0-9].[0-9][0-9].[0-9][0-9]']; do - (test ! "${srcroot}" && cd "${srcroot}"; git describe --long --abbrev=40 --match="${pattern}") > "${objroot}VERSION.tmp" 2>/dev/null - if test $? -eq 0 ; then - mv "${objroot}VERSION.tmp" "${objroot}VERSION" - break - fi - done - fi - rm -f "${objroot}VERSION.tmp" - ]) - -if test ! -e "${objroot}VERSION" ; then - if test ! -e "${srcroot}VERSION" ; then - AC_MSG_RESULT( - [Missing VERSION file, and unable to generate it; creating bogus VERSION]) - echo "0.0.0-0-g0000000000000000000000000000000000000000" > "${objroot}VERSION" - else - cp ${srcroot}VERSION ${objroot}VERSION - fi -fi -jemalloc_version=`cat "${objroot}VERSION"` -jemalloc_version_major=`echo ${jemalloc_version} | tr ".g-" " " | awk '{print [$]1}'` -jemalloc_version_minor=`echo ${jemalloc_version} | tr ".g-" " " | awk '{print [$]2}'` -jemalloc_version_bugfix=`echo ${jemalloc_version} | tr ".g-" " " | awk '{print [$]3}'` -jemalloc_version_nrev=`echo ${jemalloc_version} | tr ".g-" " " | awk '{print [$]4}'` -jemalloc_version_gid=`echo ${jemalloc_version} | tr ".g-" " " | awk '{print [$]5}'` -AC_SUBST([jemalloc_version]) -AC_SUBST([jemalloc_version_major]) -AC_SUBST([jemalloc_version_minor]) -AC_SUBST([jemalloc_version_bugfix]) -AC_SUBST([jemalloc_version_nrev]) -AC_SUBST([jemalloc_version_gid]) - -dnl Platform-specific settings. abi and RPATH can probably be determined -dnl programmatically, but doing so is error-prone, which makes it generally -dnl not worth the trouble. -dnl -dnl Define cpp macros in CPPFLAGS, rather than doing AC_DEFINE(macro), since the -dnl definitions need to be seen before any headers are included, which is a pain -dnl to make happen otherwise. -default_retain="0" -maps_coalesce="1" -DUMP_SYMS="${NM} -a" -SYM_PREFIX="" -case "${host}" in - *-*-darwin* | *-*-ios*) - abi="macho" - RPATH="" - LD_PRELOAD_VAR="DYLD_INSERT_LIBRARIES" - so="dylib" - importlib="${so}" - force_tls="0" - DSO_LDFLAGS='-shared -Wl,-install_name,$(LIBDIR)/$(@F)' - SOREV="${rev}.${so}" - sbrk_deprecated="1" - SYM_PREFIX="_" - ;; - *-*-freebsd*) - abi="elf" - AC_DEFINE([JEMALLOC_SYSCTL_VM_OVERCOMMIT], [ ]) - force_lazy_lock="1" - ;; - *-*-dragonfly*) - abi="elf" - ;; - *-*-openbsd*) - abi="elf" - force_tls="0" - ;; - *-*-bitrig*) - abi="elf" - ;; - *-*-linux-android) - dnl syscall(2) and secure_getenv(3) are exposed by _GNU_SOURCE. - JE_APPEND_VS(CPPFLAGS, -D_GNU_SOURCE) - abi="elf" - AC_DEFINE([JEMALLOC_PURGE_MADVISE_DONTNEED_ZEROS], [ ]) - AC_DEFINE([JEMALLOC_HAS_ALLOCA_H]) - AC_DEFINE([JEMALLOC_PROC_SYS_VM_OVERCOMMIT_MEMORY], [ ]) - AC_DEFINE([JEMALLOC_THREADED_INIT], [ ]) - AC_DEFINE([JEMALLOC_C11_ATOMICS]) - force_tls="0" - if test "${LG_SIZEOF_PTR}" = "3"; then - default_retain="1" - fi - ;; - *-*-linux*) - dnl syscall(2) and secure_getenv(3) are exposed by _GNU_SOURCE. - JE_APPEND_VS(CPPFLAGS, -D_GNU_SOURCE) - abi="elf" - AC_DEFINE([JEMALLOC_PURGE_MADVISE_DONTNEED_ZEROS], [ ]) - AC_DEFINE([JEMALLOC_HAS_ALLOCA_H]) - AC_DEFINE([JEMALLOC_PROC_SYS_VM_OVERCOMMIT_MEMORY], [ ]) - AC_DEFINE([JEMALLOC_THREADED_INIT], [ ]) - AC_DEFINE([JEMALLOC_USE_CXX_THROW], [ ]) - if test "${LG_SIZEOF_PTR}" = "3"; then - default_retain="1" - fi - ;; - *-*-kfreebsd*) - dnl syscall(2) and secure_getenv(3) are exposed by _GNU_SOURCE. - JE_APPEND_VS(CPPFLAGS, -D_GNU_SOURCE) - abi="elf" - AC_DEFINE([JEMALLOC_HAS_ALLOCA_H]) - AC_DEFINE([JEMALLOC_SYSCTL_VM_OVERCOMMIT], [ ]) - AC_DEFINE([JEMALLOC_THREADED_INIT], [ ]) - AC_DEFINE([JEMALLOC_USE_CXX_THROW], [ ]) - ;; - *-*-netbsd*) - AC_MSG_CHECKING([ABI]) - AC_COMPILE_IFELSE([AC_LANG_PROGRAM( -[[#ifdef __ELF__ -/* ELF */ -#else -#error aout -#endif -]])], - [abi="elf"], - [abi="aout"]) - AC_MSG_RESULT([$abi]) - ;; - *-*-solaris2*) - abi="elf" - RPATH='-Wl,-R,$(1)' - dnl Solaris needs this for sigwait(). - JE_APPEND_VS(CPPFLAGS, -D_POSIX_PTHREAD_SEMANTICS) - JE_APPEND_VS(LIBS, -lposix4 -lsocket -lnsl) - ;; - *-ibm-aix*) - if test "${LG_SIZEOF_PTR}" = "3"; then - dnl 64bit AIX - LD_PRELOAD_VAR="LDR_PRELOAD64" - else - dnl 32bit AIX - LD_PRELOAD_VAR="LDR_PRELOAD" - fi - abi="xcoff" - ;; - *-*-mingw* | *-*-cygwin*) - abi="pecoff" - force_tls="0" - maps_coalesce="0" - RPATH="" - so="dll" - if test "x$je_cv_msvc" = "xyes" ; then - importlib="lib" - DSO_LDFLAGS="-LD" - EXTRA_LDFLAGS="-link -DEBUG" - CTARGET='-Fo$@' - LDTARGET='-Fe$@' - AR='lib' - ARFLAGS='-nologo -out:' - AROUT='$@' - CC_MM= - else - importlib="${so}" - DSO_LDFLAGS="-shared" - link_whole_archive="1" - fi - case "${host}" in - *-*-cygwin*) - DUMP_SYMS="dumpbin /SYMBOLS" - ;; - *) - ;; - esac - a="lib" - libprefix="" - SOREV="${so}" - PIC_CFLAGS="" - if test "${LG_SIZEOF_PTR}" = "3"; then - default_retain="1" - fi - ;; - *) - AC_MSG_RESULT([Unsupported operating system: ${host}]) - abi="elf" - ;; -esac - -JEMALLOC_USABLE_SIZE_CONST=const -AC_CHECK_HEADERS([malloc.h], [ - AC_MSG_CHECKING([whether malloc_usable_size definition can use const argument]) - AC_COMPILE_IFELSE([AC_LANG_PROGRAM( - [#include <malloc.h> - #include <stddef.h> - size_t malloc_usable_size(const void *ptr); - ], - [])],[ - AC_MSG_RESULT([yes]) - ],[ - JEMALLOC_USABLE_SIZE_CONST= - AC_MSG_RESULT([no]) - ]) -]) -AC_DEFINE_UNQUOTED([JEMALLOC_USABLE_SIZE_CONST], [$JEMALLOC_USABLE_SIZE_CONST]) -AC_SUBST([abi]) -AC_SUBST([RPATH]) -AC_SUBST([LD_PRELOAD_VAR]) -AC_SUBST([so]) -AC_SUBST([importlib]) -AC_SUBST([o]) -AC_SUBST([a]) -AC_SUBST([exe]) -AC_SUBST([libprefix]) -AC_SUBST([link_whole_archive]) -AC_SUBST([DSO_LDFLAGS]) -AC_SUBST([EXTRA_LDFLAGS]) -AC_SUBST([SOREV]) -AC_SUBST([PIC_CFLAGS]) -AC_SUBST([CTARGET]) -AC_SUBST([LDTARGET]) -AC_SUBST([TEST_LD_MODE]) -AC_SUBST([MKLIB]) -AC_SUBST([ARFLAGS]) -AC_SUBST([AROUT]) -AC_SUBST([DUMP_SYMS]) -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], - [static __attribute__((unused)) void foo(void){}], - [], - [je_cv_attribute]) -if test "x${je_cv_attribute}" = "xyes" ; then - AC_DEFINE([JEMALLOC_HAVE_ATTR], [ ]) - if test "x${GCC}" = "xyes" -a "x${abi}" = "xelf"; then - JE_CFLAGS_ADD([-fvisibility=hidden]) - JE_CXXFLAGS_ADD([-fvisibility=hidden]) - fi -fi -dnl Check for tls_model attribute support (clang 3.0 still lacks support). -JE_CFLAGS_SAVE() -JE_CFLAGS_ADD([-Werror]) -JE_CFLAGS_ADD([-herror_on_warning]) -JE_COMPILABLE([tls_model attribute], [], - [static __thread int - __attribute__((tls_model("initial-exec"), unused)) foo; - foo = 0;], - [je_cv_tls_model]) -JE_CFLAGS_RESTORE() -dnl (Setting of JEMALLOC_TLS_MODEL is done later, after we've checked for -dnl --disable-initial-exec-tls) - -dnl Check for alloc_size attribute support. -JE_CFLAGS_SAVE() -JE_CFLAGS_ADD([-Werror]) -JE_CFLAGS_ADD([-herror_on_warning]) -JE_COMPILABLE([alloc_size attribute], [#include <stdlib.h>], - [void *foo(size_t size) __attribute__((alloc_size(1)));], - [je_cv_alloc_size]) -JE_CFLAGS_RESTORE() -if test "x${je_cv_alloc_size}" = "xyes" ; then - AC_DEFINE([JEMALLOC_HAVE_ATTR_ALLOC_SIZE], [ ]) -fi -dnl Check for format(gnu_printf, ...) attribute support. -JE_CFLAGS_SAVE() -JE_CFLAGS_ADD([-Werror]) -JE_CFLAGS_ADD([-herror_on_warning]) -JE_COMPILABLE([format(gnu_printf, ...) attribute], [#include <stdlib.h>], - [void *foo(const char *format, ...) __attribute__((format(gnu_printf, 1, 2)));], - [je_cv_format_gnu_printf]) -JE_CFLAGS_RESTORE() -if test "x${je_cv_format_gnu_printf}" = "xyes" ; then - AC_DEFINE([JEMALLOC_HAVE_ATTR_FORMAT_GNU_PRINTF], [ ]) -fi -dnl Check for format(printf, ...) attribute support. -JE_CFLAGS_SAVE() -JE_CFLAGS_ADD([-Werror]) -JE_CFLAGS_ADD([-herror_on_warning]) -JE_COMPILABLE([format(printf, ...) attribute], [#include <stdlib.h>], - [void *foo(const char *format, ...) __attribute__((format(printf, 1, 2)));], - [je_cv_format_printf]) -JE_CFLAGS_RESTORE() -if test "x${je_cv_format_printf}" = "xyes" ; then - AC_DEFINE([JEMALLOC_HAVE_ATTR_FORMAT_PRINTF], [ ]) -fi - -dnl Check for format_arg(...) attribute support. -JE_CFLAGS_SAVE() -JE_CFLAGS_ADD([-Werror]) -JE_CFLAGS_ADD([-herror_on_warning]) -JE_COMPILABLE([format(printf, ...) attribute], [#include <stdlib.h>], - [const char * __attribute__((__format_arg__(1))) foo(const char *format);], - [je_cv_format_arg]) -JE_CFLAGS_RESTORE() -if test "x${je_cv_format_arg}" = "xyes" ; then - AC_DEFINE([JEMALLOC_HAVE_ATTR_FORMAT_ARG], [ ]) -fi - -dnl Support optional additions to rpath. -AC_ARG_WITH([rpath], - [AS_HELP_STRING([--with-rpath=<rpath>], [Colon-separated rpath (ELF systems only)])], -if test "x$with_rpath" = "xno" ; then - RPATH_EXTRA= -else - RPATH_EXTRA="`echo $with_rpath | tr \":\" \" \"`" -fi, - RPATH_EXTRA= -) -AC_SUBST([RPATH_EXTRA]) - -dnl Disable rules that do automatic regeneration of configure output by default. -AC_ARG_ENABLE([autogen], - [AS_HELP_STRING([--enable-autogen], [Automatically regenerate configure output])], -if test "x$enable_autogen" = "xno" ; then - enable_autogen="0" -else - enable_autogen="1" -fi -, -enable_autogen="0" -) -AC_SUBST([enable_autogen]) - -AC_PROG_INSTALL -AC_PROG_RANLIB -AC_PATH_PROG([LD], [ld], [false], [$PATH]) -AC_PATH_PROG([AUTOCONF], [autoconf], [false], [$PATH]) - -dnl Enable documentation -AC_ARG_ENABLE([doc], - [AS_HELP_STRING([--enable-documentation], [Build documentation])], -if test "x$enable_doc" = "xno" ; then - enable_doc="0" -else - enable_doc="1" -fi -, -enable_doc="1" -) -AC_SUBST([enable_doc]) - -dnl Enable shared libs -AC_ARG_ENABLE([shared], - [AS_HELP_STRING([--enable-shared], [Build shared libaries])], -if test "x$enable_shared" = "xno" ; then - enable_shared="0" -else - enable_shared="1" -fi -, -enable_shared="1" -) -AC_SUBST([enable_shared]) - -dnl Enable static libs -AC_ARG_ENABLE([static], - [AS_HELP_STRING([--enable-static], [Build static libaries])], -if test "x$enable_static" = "xno" ; then - enable_static="0" -else - enable_static="1" -fi -, -enable_static="1" -) -AC_SUBST([enable_static]) - -if test "$enable_shared$enable_static" = "00" ; then - AC_MSG_ERROR([Please enable one of shared or static builds]) -fi - -dnl Perform no name mangling by default. -AC_ARG_WITH([mangling], - [AS_HELP_STRING([--with-mangling=<map>], [Mangle symbols in <map>])], - [mangling_map="$with_mangling"], [mangling_map=""]) - -dnl Do not prefix public APIs by default. -AC_ARG_WITH([jemalloc_prefix], - [AS_HELP_STRING([--with-jemalloc-prefix=<prefix>], [Prefix to prepend to all public APIs])], - [JEMALLOC_PREFIX="$with_jemalloc_prefix"], - [if test "x$abi" != "xmacho" -a "x$abi" != "xpecoff"; then - JEMALLOC_PREFIX="" -else - JEMALLOC_PREFIX="je_" -fi] -) -if test "x$JEMALLOC_PREFIX" = "x" ; then - AC_DEFINE([JEMALLOC_IS_MALLOC]) -else - JEMALLOC_CPREFIX=`echo ${JEMALLOC_PREFIX} | tr "a-z" "A-Z"` - AC_DEFINE_UNQUOTED([JEMALLOC_PREFIX], ["$JEMALLOC_PREFIX"]) - AC_DEFINE_UNQUOTED([JEMALLOC_CPREFIX], ["$JEMALLOC_CPREFIX"]) -fi -AC_SUBST([JEMALLOC_PREFIX]) -AC_SUBST([JEMALLOC_CPREFIX]) - -AC_ARG_WITH([export], - [AS_HELP_STRING([--without-export], [disable exporting jemalloc public APIs])], - [if test "x$with_export" = "xno"; then - AC_DEFINE([JEMALLOC_EXPORT],[]) -fi] -) - -public_syms="aligned_alloc calloc dallocx free mallctl mallctlbymib mallctlnametomib malloc malloc_conf malloc_message malloc_stats_print malloc_usable_size mallocx smallocx_${jemalloc_version_gid} nallocx posix_memalign rallocx realloc sallocx sdallocx xallocx" -dnl Check for additional platform-specific public API functions. -AC_CHECK_FUNC([memalign], - [AC_DEFINE([JEMALLOC_OVERRIDE_MEMALIGN], [ ]) - public_syms="${public_syms} memalign"]) -AC_CHECK_FUNC([valloc], - [AC_DEFINE([JEMALLOC_OVERRIDE_VALLOC], [ ]) - public_syms="${public_syms} valloc"]) - -dnl Check for allocator-related functions that should be wrapped. -wrap_syms= -if test "x${JEMALLOC_PREFIX}" = "x" ; then - AC_CHECK_FUNC([__libc_calloc], - [AC_DEFINE([JEMALLOC_OVERRIDE___LIBC_CALLOC], [ ]) - wrap_syms="${wrap_syms} __libc_calloc"]) - AC_CHECK_FUNC([__libc_free], - [AC_DEFINE([JEMALLOC_OVERRIDE___LIBC_FREE], [ ]) - wrap_syms="${wrap_syms} __libc_free"]) - AC_CHECK_FUNC([__libc_malloc], - [AC_DEFINE([JEMALLOC_OVERRIDE___LIBC_MALLOC], [ ]) - wrap_syms="${wrap_syms} __libc_malloc"]) - AC_CHECK_FUNC([__libc_memalign], - [AC_DEFINE([JEMALLOC_OVERRIDE___LIBC_MEMALIGN], [ ]) - wrap_syms="${wrap_syms} __libc_memalign"]) - AC_CHECK_FUNC([__libc_realloc], - [AC_DEFINE([JEMALLOC_OVERRIDE___LIBC_REALLOC], [ ]) - wrap_syms="${wrap_syms} __libc_realloc"]) - AC_CHECK_FUNC([__libc_valloc], - [AC_DEFINE([JEMALLOC_OVERRIDE___LIBC_VALLOC], [ ]) - wrap_syms="${wrap_syms} __libc_valloc"]) - AC_CHECK_FUNC([__posix_memalign], - [AC_DEFINE([JEMALLOC_OVERRIDE___POSIX_MEMALIGN], [ ]) - wrap_syms="${wrap_syms} __posix_memalign"]) -fi - -case "${host}" in - *-*-mingw* | *-*-cygwin*) - wrap_syms="${wrap_syms} tls_callback" - ;; - *) - ;; -esac - -dnl Mangle library-private APIs. -AC_ARG_WITH([private_namespace], - [AS_HELP_STRING([--with-private-namespace=<prefix>], [Prefix to prepend to all library-private APIs])], - [JEMALLOC_PRIVATE_NAMESPACE="${with_private_namespace}je_"], - [JEMALLOC_PRIVATE_NAMESPACE="je_"] -) -AC_DEFINE_UNQUOTED([JEMALLOC_PRIVATE_NAMESPACE], [$JEMALLOC_PRIVATE_NAMESPACE]) -private_namespace="$JEMALLOC_PRIVATE_NAMESPACE" -AC_SUBST([private_namespace]) - -dnl Do not add suffix to installed files by default. -AC_ARG_WITH([install_suffix], - [AS_HELP_STRING([--with-install-suffix=<suffix>], [Suffix to append to all installed files])], - [INSTALL_SUFFIX="$with_install_suffix"], - [INSTALL_SUFFIX=] -) -install_suffix="$INSTALL_SUFFIX" -AC_SUBST([install_suffix]) - -dnl Specify default malloc_conf. -AC_ARG_WITH([malloc_conf], - [AS_HELP_STRING([--with-malloc-conf=<malloc_conf>], [config.malloc_conf options string])], - [JEMALLOC_CONFIG_MALLOC_CONF="$with_malloc_conf"], - [JEMALLOC_CONFIG_MALLOC_CONF=""] -) -config_malloc_conf="$JEMALLOC_CONFIG_MALLOC_CONF" -AC_DEFINE_UNQUOTED([JEMALLOC_CONFIG_MALLOC_CONF], ["$config_malloc_conf"]) - -dnl Substitute @je_@ in jemalloc_protos.h.in, primarily to make generation of -dnl jemalloc_protos_jet.h easy. -je_="je_" -AC_SUBST([je_]) - -cfgoutputs_in="Makefile.in" -cfgoutputs_in="${cfgoutputs_in} jemalloc.pc.in" -cfgoutputs_in="${cfgoutputs_in} doc/html.xsl.in" -cfgoutputs_in="${cfgoutputs_in} doc/manpages.xsl.in" -cfgoutputs_in="${cfgoutputs_in} doc/jemalloc.xml.in" -cfgoutputs_in="${cfgoutputs_in} include/jemalloc/jemalloc_macros.h.in" -cfgoutputs_in="${cfgoutputs_in} include/jemalloc/jemalloc_protos.h.in" -cfgoutputs_in="${cfgoutputs_in} include/jemalloc/jemalloc_typedefs.h.in" -cfgoutputs_in="${cfgoutputs_in} include/jemalloc/internal/jemalloc_preamble.h.in" -cfgoutputs_in="${cfgoutputs_in} test/test.sh.in" -cfgoutputs_in="${cfgoutputs_in} test/include/test/jemalloc_test.h.in" - -cfgoutputs_out="Makefile" -cfgoutputs_out="${cfgoutputs_out} jemalloc.pc" -cfgoutputs_out="${cfgoutputs_out} doc/html.xsl" -cfgoutputs_out="${cfgoutputs_out} doc/manpages.xsl" -cfgoutputs_out="${cfgoutputs_out} doc/jemalloc.xml" -cfgoutputs_out="${cfgoutputs_out} include/jemalloc/jemalloc_macros.h" -cfgoutputs_out="${cfgoutputs_out} include/jemalloc/jemalloc_protos.h" -cfgoutputs_out="${cfgoutputs_out} include/jemalloc/jemalloc_typedefs.h" -cfgoutputs_out="${cfgoutputs_out} include/jemalloc/internal/jemalloc_preamble.h" -cfgoutputs_out="${cfgoutputs_out} test/test.sh" -cfgoutputs_out="${cfgoutputs_out} test/include/test/jemalloc_test.h" - -cfgoutputs_tup="Makefile" -cfgoutputs_tup="${cfgoutputs_tup} jemalloc.pc:jemalloc.pc.in" -cfgoutputs_tup="${cfgoutputs_tup} doc/html.xsl:doc/html.xsl.in" -cfgoutputs_tup="${cfgoutputs_tup} doc/manpages.xsl:doc/manpages.xsl.in" -cfgoutputs_tup="${cfgoutputs_tup} doc/jemalloc.xml:doc/jemalloc.xml.in" -cfgoutputs_tup="${cfgoutputs_tup} include/jemalloc/jemalloc_macros.h:include/jemalloc/jemalloc_macros.h.in" -cfgoutputs_tup="${cfgoutputs_tup} include/jemalloc/jemalloc_protos.h:include/jemalloc/jemalloc_protos.h.in" -cfgoutputs_tup="${cfgoutputs_tup} include/jemalloc/jemalloc_typedefs.h:include/jemalloc/jemalloc_typedefs.h.in" -cfgoutputs_tup="${cfgoutputs_tup} include/jemalloc/internal/jemalloc_preamble.h" -cfgoutputs_tup="${cfgoutputs_tup} test/test.sh:test/test.sh.in" -cfgoutputs_tup="${cfgoutputs_tup} test/include/test/jemalloc_test.h:test/include/test/jemalloc_test.h.in" - -cfghdrs_in="include/jemalloc/jemalloc_defs.h.in" -cfghdrs_in="${cfghdrs_in} include/jemalloc/internal/jemalloc_internal_defs.h.in" -cfghdrs_in="${cfghdrs_in} include/jemalloc/internal/private_symbols.sh" -cfghdrs_in="${cfghdrs_in} include/jemalloc/internal/private_namespace.sh" -cfghdrs_in="${cfghdrs_in} include/jemalloc/internal/public_namespace.sh" -cfghdrs_in="${cfghdrs_in} include/jemalloc/internal/public_unnamespace.sh" -cfghdrs_in="${cfghdrs_in} include/jemalloc/jemalloc_rename.sh" -cfghdrs_in="${cfghdrs_in} include/jemalloc/jemalloc_mangle.sh" -cfghdrs_in="${cfghdrs_in} include/jemalloc/jemalloc.sh" -cfghdrs_in="${cfghdrs_in} test/include/test/jemalloc_test_defs.h.in" - -cfghdrs_out="include/jemalloc/jemalloc_defs.h" -cfghdrs_out="${cfghdrs_out} include/jemalloc/jemalloc${install_suffix}.h" -cfghdrs_out="${cfghdrs_out} include/jemalloc/internal/private_symbols.awk" -cfghdrs_out="${cfghdrs_out} include/jemalloc/internal/private_symbols_jet.awk" -cfghdrs_out="${cfghdrs_out} include/jemalloc/internal/public_symbols.txt" -cfghdrs_out="${cfghdrs_out} include/jemalloc/internal/public_namespace.h" -cfghdrs_out="${cfghdrs_out} include/jemalloc/internal/public_unnamespace.h" -cfghdrs_out="${cfghdrs_out} include/jemalloc/jemalloc_protos_jet.h" -cfghdrs_out="${cfghdrs_out} include/jemalloc/jemalloc_rename.h" -cfghdrs_out="${cfghdrs_out} include/jemalloc/jemalloc_mangle.h" -cfghdrs_out="${cfghdrs_out} include/jemalloc/jemalloc_mangle_jet.h" -cfghdrs_out="${cfghdrs_out} include/jemalloc/internal/jemalloc_internal_defs.h" -cfghdrs_out="${cfghdrs_out} test/include/test/jemalloc_test_defs.h" - -cfghdrs_tup="include/jemalloc/jemalloc_defs.h:include/jemalloc/jemalloc_defs.h.in" -cfghdrs_tup="${cfghdrs_tup} include/jemalloc/internal/jemalloc_internal_defs.h:include/jemalloc/internal/jemalloc_internal_defs.h.in" -cfghdrs_tup="${cfghdrs_tup} test/include/test/jemalloc_test_defs.h:test/include/test/jemalloc_test_defs.h.in" - -dnl ============================================================================ -dnl jemalloc build options. -dnl - -dnl Do not compile with debugging by default. -AC_ARG_ENABLE([debug], - [AS_HELP_STRING([--enable-debug], - [Build debugging code])], -[if test "x$enable_debug" = "xno" ; then - enable_debug="0" -else - enable_debug="1" -fi -], -[enable_debug="0"] -) -if test "x$enable_debug" = "x1" ; then - AC_DEFINE([JEMALLOC_DEBUG], [ ]) -fi -if test "x$enable_debug" = "x1" ; then - AC_DEFINE([JEMALLOC_DEBUG], [ ]) -fi -AC_SUBST([enable_debug]) - -dnl Only optimize if not debugging. -if test "x$enable_debug" = "x0" ; then - if test "x$GCC" = "xyes" ; then - JE_CFLAGS_ADD([-O3]) - JE_CXXFLAGS_ADD([-O3]) - JE_CFLAGS_ADD([-funroll-loops]) - elif test "x$je_cv_msvc" = "xyes" ; then - JE_CFLAGS_ADD([-O2]) - JE_CXXFLAGS_ADD([-O2]) - else - JE_CFLAGS_ADD([-O]) - JE_CXXFLAGS_ADD([-O]) - fi -fi - -dnl Enable statistics calculation by default. -AC_ARG_ENABLE([stats], - [AS_HELP_STRING([--disable-stats], - [Disable statistics calculation/reporting])], -[if test "x$enable_stats" = "xno" ; then - enable_stats="0" -else - enable_stats="1" -fi -], -[enable_stats="1"] -) -if test "x$enable_stats" = "x1" ; then - AC_DEFINE([JEMALLOC_STATS], [ ]) -fi -AC_SUBST([enable_stats]) - -dnl Do not enable smallocx by default. -AC_ARG_ENABLE([experimental_smallocx], - [AS_HELP_STRING([--enable-experimental-smallocx], [Enable experimental smallocx API])], -[if test "x$enable_experimental_smallocx" = "xno" ; then -enable_experimental_smallocx="0" -else -enable_experimental_smallocx="1" -fi -], -[enable_experimental_smallocx="0"] -) -if test "x$enable_experimental_smallocx" = "x1" ; then - AC_DEFINE([JEMALLOC_EXPERIMENTAL_SMALLOCX_API]) -fi -AC_SUBST([enable_experimental_smallocx]) - -dnl Do not enable profiling by default. -AC_ARG_ENABLE([prof], - [AS_HELP_STRING([--enable-prof], [Enable allocation profiling])], -[if test "x$enable_prof" = "xno" ; then - enable_prof="0" -else - enable_prof="1" -fi -], -[enable_prof="0"] -) -if test "x$enable_prof" = "x1" ; then - backtrace_method="" -else - backtrace_method="N/A" -fi - -AC_ARG_ENABLE([prof-libunwind], - [AS_HELP_STRING([--enable-prof-libunwind], [Use libunwind for backtracing])], -[if test "x$enable_prof_libunwind" = "xno" ; then - enable_prof_libunwind="0" -else - enable_prof_libunwind="1" -fi -], -[enable_prof_libunwind="0"] -) -AC_ARG_WITH([static_libunwind], - [AS_HELP_STRING([--with-static-libunwind=<libunwind.a>], - [Path to static libunwind library; use rather than dynamically linking])], -if test "x$with_static_libunwind" = "xno" ; then - LUNWIND="-lunwind" -else - if test ! -f "$with_static_libunwind" ; then - AC_MSG_ERROR([Static libunwind not found: $with_static_libunwind]) - fi - LUNWIND="$with_static_libunwind" -fi, - LUNWIND="-lunwind" -) -if test "x$backtrace_method" = "x" -a "x$enable_prof_libunwind" = "x1" ; then - AC_CHECK_HEADERS([libunwind.h], , [enable_prof_libunwind="0"]) - if test "x$LUNWIND" = "x-lunwind" ; then - AC_CHECK_LIB([unwind], [unw_backtrace], [JE_APPEND_VS(LIBS, $LUNWIND)], - [enable_prof_libunwind="0"]) - else - JE_APPEND_VS(LIBS, $LUNWIND) - fi - if test "x${enable_prof_libunwind}" = "x1" ; then - backtrace_method="libunwind" - AC_DEFINE([JEMALLOC_PROF_LIBUNWIND], [ ]) - fi -fi - -AC_ARG_ENABLE([prof-libgcc], - [AS_HELP_STRING([--disable-prof-libgcc], - [Do not use libgcc for backtracing])], -[if test "x$enable_prof_libgcc" = "xno" ; then - enable_prof_libgcc="0" -else - enable_prof_libgcc="1" -fi -], -[enable_prof_libgcc="1"] -) -if test "x$backtrace_method" = "x" -a "x$enable_prof_libgcc" = "x1" \ - -a "x$GCC" = "xyes" ; then - AC_CHECK_HEADERS([unwind.h], , [enable_prof_libgcc="0"]) - if test "x${enable_prof_libgcc}" = "x1" ; then - AC_CHECK_LIB([gcc], [_Unwind_Backtrace], [JE_APPEND_VS(LIBS, -lgcc)], [enable_prof_libgcc="0"]) - fi - if test "x${enable_prof_libgcc}" = "x1" ; then - backtrace_method="libgcc" - AC_DEFINE([JEMALLOC_PROF_LIBGCC], [ ]) - fi -else - enable_prof_libgcc="0" -fi - -AC_ARG_ENABLE([prof-gcc], - [AS_HELP_STRING([--disable-prof-gcc], - [Do not use gcc intrinsics for backtracing])], -[if test "x$enable_prof_gcc" = "xno" ; then - enable_prof_gcc="0" -else - enable_prof_gcc="1" -fi -], -[enable_prof_gcc="1"] -) -if test "x$backtrace_method" = "x" -a "x$enable_prof_gcc" = "x1" \ - -a "x$GCC" = "xyes" ; then - JE_CFLAGS_ADD([-fno-omit-frame-pointer]) - backtrace_method="gcc intrinsics" - AC_DEFINE([JEMALLOC_PROF_GCC], [ ]) -else - enable_prof_gcc="0" -fi - -if test "x$backtrace_method" = "x" ; then - backtrace_method="none (disabling profiling)" - enable_prof="0" -fi -AC_MSG_CHECKING([configured backtracing method]) -AC_MSG_RESULT([$backtrace_method]) -if test "x$enable_prof" = "x1" ; then - dnl Heap profiling uses the log(3) function. - JE_APPEND_VS(LIBS, $LM) - - AC_DEFINE([JEMALLOC_PROF], [ ]) -fi -AC_SUBST([enable_prof]) - -dnl Indicate whether adjacent virtual memory mappings automatically coalesce -dnl (and fragment on demand). -if test "x${maps_coalesce}" = "x1" ; then - AC_DEFINE([JEMALLOC_MAPS_COALESCE], [ ]) -fi - -dnl Indicate whether to retain memory (rather than using munmap()) by default. -if test "x$default_retain" = "x1" ; then - AC_DEFINE([JEMALLOC_RETAIN], [ ]) -fi - -dnl Enable allocation from DSS if supported by the OS. -have_dss="1" -dnl Check whether the BSD/SUSv1 sbrk() exists. If not, disable DSS support. -AC_CHECK_FUNC([sbrk], [have_sbrk="1"], [have_sbrk="0"]) -if test "x$have_sbrk" = "x1" ; then - if test "x$sbrk_deprecated" = "x1" ; then - AC_MSG_RESULT([Disabling dss allocation because sbrk is deprecated]) - have_dss="0" - fi -else - have_dss="0" -fi - -if test "x$have_dss" = "x1" ; then - AC_DEFINE([JEMALLOC_DSS], [ ]) -fi - -dnl Support the junk/zero filling option by default. -AC_ARG_ENABLE([fill], - [AS_HELP_STRING([--disable-fill], [Disable support for junk/zero filling])], -[if test "x$enable_fill" = "xno" ; then - enable_fill="0" -else - enable_fill="1" -fi -], -[enable_fill="1"] -) -if test "x$enable_fill" = "x1" ; then - AC_DEFINE([JEMALLOC_FILL], [ ]) -fi -AC_SUBST([enable_fill]) - -dnl Disable utrace(2)-based tracing by default. -AC_ARG_ENABLE([utrace], - [AS_HELP_STRING([--enable-utrace], [Enable utrace(2)-based tracing])], -[if test "x$enable_utrace" = "xno" ; then - enable_utrace="0" -else - enable_utrace="1" -fi -], -[enable_utrace="0"] -) -JE_COMPILABLE([utrace(2)], [ -#include <sys/types.h> -#include <sys/param.h> -#include <sys/time.h> -#include <sys/uio.h> -#include <sys/ktrace.h> -], [ - utrace((void *)0, 0); -], [je_cv_utrace]) -if test "x${je_cv_utrace}" = "xno" ; then - enable_utrace="0" -fi -if test "x$enable_utrace" = "x1" ; then - AC_DEFINE([JEMALLOC_UTRACE], [ ]) -fi -AC_SUBST([enable_utrace]) - -dnl Do not support the xmalloc option by default. -AC_ARG_ENABLE([xmalloc], - [AS_HELP_STRING([--enable-xmalloc], [Support xmalloc option])], -[if test "x$enable_xmalloc" = "xno" ; then - enable_xmalloc="0" -else - enable_xmalloc="1" -fi -], -[enable_xmalloc="0"] -) -if test "x$enable_xmalloc" = "x1" ; then - AC_DEFINE([JEMALLOC_XMALLOC], [ ]) -fi -AC_SUBST([enable_xmalloc]) - -dnl Support cache-oblivious allocation alignment by default. -AC_ARG_ENABLE([cache-oblivious], - [AS_HELP_STRING([--disable-cache-oblivious], - [Disable support for cache-oblivious allocation alignment])], -[if test "x$enable_cache_oblivious" = "xno" ; then - enable_cache_oblivious="0" -else - enable_cache_oblivious="1" -fi -], -[enable_cache_oblivious="1"] -) -if test "x$enable_cache_oblivious" = "x1" ; then - AC_DEFINE([JEMALLOC_CACHE_OBLIVIOUS], [ ]) -fi -AC_SUBST([enable_cache_oblivious]) - -dnl Do not log by default. -AC_ARG_ENABLE([log], - [AS_HELP_STRING([--enable-log], [Support debug logging])], -[if test "x$enable_log" = "xno" ; then - enable_log="0" -else - enable_log="1" -fi -], -[enable_log="0"] -) -if test "x$enable_log" = "x1" ; then - AC_DEFINE([JEMALLOC_LOG], [ ]) -fi -AC_SUBST([enable_log]) - -dnl Do not use readlinkat by default -AC_ARG_ENABLE([readlinkat], - [AS_HELP_STRING([--enable-readlinkat], [Use readlinkat over readlink])], -[if test "x$enable_readlinkat" = "xno" ; then - enable_readlinkat="0" -else - enable_readlinkat="1" -fi -], -[enable_readlinkat="0"] -) -if test "x$enable_readlinkat" = "x1" ; then - AC_DEFINE([JEMALLOC_READLINKAT], [ ]) -fi -AC_SUBST([enable_readlinkat]) - -dnl Avoid extra safety checks by default -AC_ARG_ENABLE([opt-safety-checks], - [AS_HELP_STRING([--enable-opt-safety-checks], - [Perform certain low-overhead checks, even in opt mode])], -[if test "x$enable_opt_safety_checks" = "xno" ; then - enable_opt_safety_checks="0" -else - enable_opt_safety_checks="1" -fi -], -[enable_opt_safety_checks="0"] -) -if test "x$enable_opt_safety_checks" = "x1" ; then - AC_DEFINE([JEMALLOC_OPT_SAFETY_CHECKS], [ ]) -fi -AC_SUBST([enable_opt_safety_checks]) - -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 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 that jemalloc currently has a chance of functioning on without modification. -dnl We additionally assume ffs[ll]() or __builtin_ffs[ll]() are defined if -dnl ffsl() or __builtin_ffsl() are defined, respectively. -JE_COMPILABLE([a program using __builtin_ffsl], [ -#include <stdio.h> -#include <strings.h> -#include <string.h> -], [ - { - int rv = __builtin_ffsl(0x08); - printf("%d\n", rv); - } -], [je_cv_gcc_builtin_ffsl]) -if test "x${je_cv_gcc_builtin_ffsl}" = "xyes" ; then - AC_DEFINE([JEMALLOC_INTERNAL_FFSLL], [__builtin_ffsll]) - AC_DEFINE([JEMALLOC_INTERNAL_FFSL], [__builtin_ffsl]) - AC_DEFINE([JEMALLOC_INTERNAL_FFS], [__builtin_ffs]) -else - JE_COMPILABLE([a program using ffsl], [ - #include <stdio.h> - #include <strings.h> - #include <string.h> - ], [ - { - int rv = ffsl(0x08); - printf("%d\n", rv); - } - ], [je_cv_function_ffsl]) - if test "x${je_cv_function_ffsl}" = "xyes" ; then - AC_DEFINE([JEMALLOC_INTERNAL_FFSLL], [ffsll]) - AC_DEFINE([JEMALLOC_INTERNAL_FFSL], [ffsl]) - AC_DEFINE([JEMALLOC_INTERNAL_FFS], [ffs]) - else - AC_MSG_ERROR([Cannot build without ffsl(3) or __builtin_ffsl()]) - fi -fi - -JE_COMPILABLE([a program using __builtin_popcountl], [ -#include <stdio.h> -#include <strings.h> -#include <string.h> -], [ - { - int rv = __builtin_popcountl(0x08); - printf("%d\n", rv); - } -], [je_cv_gcc_builtin_popcountl]) -if test "x${je_cv_gcc_builtin_popcountl}" = "xyes" ; then - AC_DEFINE([JEMALLOC_INTERNAL_POPCOUNT], [__builtin_popcount]) - AC_DEFINE([JEMALLOC_INTERNAL_POPCOUNTL], [__builtin_popcountl]) -fi - -AC_ARG_WITH([lg_quantum], - [AS_HELP_STRING([--with-lg-quantum=<lg-quantum>], - [Base 2 log of minimum allocation alignment])], - [LG_QUANTA="$with_lg_quantum"], - [LG_QUANTA="3 4"]) -if test "x$with_lg_quantum" != "x" ; then - AC_DEFINE_UNQUOTED([LG_QUANTUM], [$with_lg_quantum]) -fi - -AC_ARG_WITH([lg_page], - [AS_HELP_STRING([--with-lg-page=<lg-page>], [Base 2 log of system page size])], - [LG_PAGE="$with_lg_page"], [LG_PAGE="detect"]) -if test "x$LG_PAGE" = "xdetect"; then - AC_CACHE_CHECK([LG_PAGE], - [je_cv_lg_page], - AC_RUN_IFELSE([AC_LANG_PROGRAM( -[[ -#include <strings.h> -#ifdef _WIN32 -#include <windows.h> -#else -#include <unistd.h> -#endif -#include <stdio.h> -]], -[[ - int result; - FILE *f; - -#ifdef _WIN32 - SYSTEM_INFO si; - GetSystemInfo(&si); - result = si.dwPageSize; -#else - result = sysconf(_SC_PAGESIZE); -#endif - if (result == -1) { - return 1; - } - result = JEMALLOC_INTERNAL_FFSL(result) - 1; - - f = fopen("conftest.out", "w"); - if (f == NULL) { - return 1; - } - fprintf(f, "%d", result); - fclose(f); - - return 0; -]])], - [je_cv_lg_page=`cat conftest.out`], - [je_cv_lg_page=undefined], - [je_cv_lg_page=12])) -fi -if test "x${je_cv_lg_page}" != "x" ; then - LG_PAGE="${je_cv_lg_page}" -fi -if test "x${LG_PAGE}" != "xundefined" ; then - AC_DEFINE_UNQUOTED([LG_PAGE], [$LG_PAGE]) -else - AC_MSG_ERROR([cannot determine value for LG_PAGE]) -fi - -AC_ARG_WITH([lg_hugepage], - [AS_HELP_STRING([--with-lg-hugepage=<lg-hugepage>], - [Base 2 log of system huge page size])], - [je_cv_lg_hugepage="${with_lg_hugepage}"], - [je_cv_lg_hugepage=""]) -if test "x${je_cv_lg_hugepage}" = "x" ; then - dnl Look in /proc/meminfo (Linux-specific) for information on the default huge - dnl page size, if any. The relevant line looks like: - dnl - dnl Hugepagesize: 2048 kB - if test -e "/proc/meminfo" ; then - hpsk=[`cat /proc/meminfo 2>/dev/null | \ - grep -e '^Hugepagesize:[[:space:]]\+[0-9]\+[[:space:]]kB$' | \ - awk '{print $2}'`] - if test "x${hpsk}" != "x" ; then - je_cv_lg_hugepage=10 - while test "${hpsk}" -gt 1 ; do - hpsk="$((hpsk / 2))" - je_cv_lg_hugepage="$((je_cv_lg_hugepage + 1))" - done - fi - fi - - dnl Set default if unable to automatically configure. - if test "x${je_cv_lg_hugepage}" = "x" ; then - je_cv_lg_hugepage=21 - fi -fi -if test "x${LG_PAGE}" != "xundefined" -a \ - "${je_cv_lg_hugepage}" -lt "${LG_PAGE}" ; then - AC_MSG_ERROR([Huge page size (2^${je_cv_lg_hugepage}) must be at least page size (2^${LG_PAGE})]) -fi -AC_DEFINE_UNQUOTED([LG_HUGEPAGE], [${je_cv_lg_hugepage}]) - -dnl ============================================================================ -dnl Enable libdl by default. -AC_ARG_ENABLE([libdl], - [AS_HELP_STRING([--disable-libdl], - [Do not use libdl])], -[if test "x$enable_libdl" = "xno" ; then - enable_libdl="0" -else - enable_libdl="1" -fi -], -[enable_libdl="1"] -) -AC_SUBST([libdl]) - -dnl ============================================================================ -dnl Configure pthreads. - -if test "x$abi" != "xpecoff" ; then - AC_DEFINE([JEMALLOC_HAVE_PTHREAD], [ ]) - 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 first, but try libc too before failing. - AC_CHECK_LIB([pthread], [pthread_create], [JE_APPEND_VS(LIBS, -pthread)], - [AC_SEARCH_LIBS([pthread_create], , , - AC_MSG_ERROR([libpthread is missing]))]) - wrap_syms="${wrap_syms} pthread_create" - have_pthread="1" - -dnl Check if we have dlsym support. - if test "x$enable_libdl" = "x1" ; then - have_dlsym="1" - AC_CHECK_HEADERS([dlfcn.h], - AC_CHECK_FUNC([dlsym], [], - [AC_CHECK_LIB([dl], [dlsym], [LIBS="$LIBS -ldl"], [have_dlsym="0"])]), - [have_dlsym="0"]) - if test "x$have_dlsym" = "x1" ; then - AC_DEFINE([JEMALLOC_HAVE_DLSYM], [ ]) - fi - else - have_dlsym="0" - fi - - 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 - dnl Check if pthread_setname_np is available with the expected API. - JE_COMPILABLE([pthread_setname_np(3)], [ -#include <pthread.h> -], [ - pthread_setname_np(pthread_self(), "setname_test"); -], [je_cv_pthread_setname_np]) - if test "x${je_cv_pthread_setname_np}" = "xyes" ; then - AC_DEFINE([JEMALLOC_HAVE_PTHREAD_SETNAME_NP], [ ]) - fi -fi - -JE_APPEND_VS(CPPFLAGS, -D_REENTRANT) - -dnl Check whether clock_gettime(2) is in libc or librt. -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. -AC_CHECK_FUNC([secure_getenv], - [have_secure_getenv="1"], - [have_secure_getenv="0"] - ) -if test "x$have_secure_getenv" = "x1" ; then - AC_DEFINE([JEMALLOC_HAVE_SECURE_GETENV], [ ]) -fi - -dnl Check if the GNU-specific sched_getcpu function exists. -AC_CHECK_FUNC([sched_getcpu], - [have_sched_getcpu="1"], - [have_sched_getcpu="0"] - ) -if test "x$have_sched_getcpu" = "x1" ; then - AC_DEFINE([JEMALLOC_HAVE_SCHED_GETCPU], [ ]) -fi - -dnl Check if the GNU-specific sched_setaffinity function exists. -AC_CHECK_FUNC([sched_setaffinity], - [have_sched_setaffinity="1"], - [have_sched_setaffinity="0"] - ) -if test "x$have_sched_setaffinity" = "x1" ; then - AC_DEFINE([JEMALLOC_HAVE_SCHED_SETAFFINITY], [ ]) -fi - -dnl Check if the Solaris/BSD issetugid function exists. -AC_CHECK_FUNC([issetugid], - [have_issetugid="1"], - [have_issetugid="0"] - ) -if test "x$have_issetugid" = "x1" ; then - AC_DEFINE([JEMALLOC_HAVE_ISSETUGID], [ ]) -fi - -dnl Check whether the BSD-specific _malloc_thread_cleanup() exists. If so, use -dnl it rather than pthreads TSD cleanup functions to support cleanup during -dnl thread exit, in order to avoid pthreads library recursion during -dnl bootstrapping. -AC_CHECK_FUNC([_malloc_thread_cleanup], - [have__malloc_thread_cleanup="1"], - [have__malloc_thread_cleanup="0"] - ) -if test "x$have__malloc_thread_cleanup" = "x1" ; then - AC_DEFINE([JEMALLOC_MALLOC_THREAD_CLEANUP], [ ]) - wrap_syms="${wrap_syms} _malloc_thread_cleanup" - force_tls="1" -fi - -dnl Check whether the BSD-specific _pthread_mutex_init_calloc_cb() exists. If -dnl so, mutex initialization causes allocation, and we need to implement this -dnl callback function in order to prevent recursive allocation. -AC_CHECK_FUNC([_pthread_mutex_init_calloc_cb], - [have__pthread_mutex_init_calloc_cb="1"], - [have__pthread_mutex_init_calloc_cb="0"] - ) -if test "x$have__pthread_mutex_init_calloc_cb" = "x1" ; then - AC_DEFINE([JEMALLOC_MUTEX_INIT_CB]) - wrap_syms="${wrap_syms} _malloc_prefork _malloc_postfork" -fi - -dnl Disable lazy locking by default. -AC_ARG_ENABLE([lazy_lock], - [AS_HELP_STRING([--enable-lazy-lock], - [Enable lazy locking (only lock when multi-threaded)])], -[if test "x$enable_lazy_lock" = "xno" ; then - enable_lazy_lock="0" -else - enable_lazy_lock="1" -fi -], -[enable_lazy_lock=""] -) -if test "x${enable_lazy_lock}" = "x" ; then - if test "x${force_lazy_lock}" = "x1" ; then - 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 -if test "x$enable_lazy_lock" = "x1" ; then - if test "x$have_dlsym" = "x1" ; then - AC_DEFINE([JEMALLOC_LAZY_LOCK], [ ]) - else - AC_MSG_ERROR([Missing dlsym support: lazy-lock cannot be enabled.]) - fi -fi -AC_SUBST([enable_lazy_lock]) - -dnl Automatically configure TLS. -if test "x${force_tls}" = "x1" ; then - enable_tls="1" -elif test "x${force_tls}" = "x0" ; then - enable_tls="0" -else - enable_tls="1" -fi -if test "x${enable_tls}" = "x1" ; then -AC_MSG_CHECKING([for TLS]) -AC_COMPILE_IFELSE([AC_LANG_PROGRAM( -[[ - __thread int x; -]], [[ - x = 42; - - return 0; -]])], - AC_MSG_RESULT([yes]), - AC_MSG_RESULT([no]) - enable_tls="0") -else - enable_tls="0" -fi -AC_SUBST([enable_tls]) -if test "x${enable_tls}" = "x1" ; then - AC_DEFINE_UNQUOTED([JEMALLOC_TLS], [ ]) -fi - -dnl ============================================================================ -dnl Check for C11 atomics. - -JE_COMPILABLE([C11 atomics], [ -#include <stdint.h> -#if (__STDC_VERSION__ >= 201112L) && !defined(__STDC_NO_ATOMICS__) -#include <stdatomic.h> -#else -#error Atomics not available -#endif -], [ - uint64_t *p = (uint64_t *)0; - uint64_t x = 1; - volatile atomic_uint_least64_t *a = (volatile atomic_uint_least64_t *)p; - uint64_t r = atomic_fetch_add(a, x) + x; - return r == 0; -], [je_cv_c11_atomics]) -if test "x${je_cv_c11_atomics}" = "xyes" ; then - AC_DEFINE([JEMALLOC_C11_ATOMICS]) -fi - -dnl ============================================================================ -dnl Check for GCC-style __atomic atomics. - -JE_COMPILABLE([GCC __atomic atomics], [ -], [ - int x = 0; - int val = 1; - int y = __atomic_fetch_add(&x, val, __ATOMIC_RELAXED); - int after_add = x; - return after_add == 1; -], [je_cv_gcc_atomic_atomics]) -if test "x${je_cv_gcc_atomic_atomics}" = "xyes" ; then - AC_DEFINE([JEMALLOC_GCC_ATOMIC_ATOMICS]) - - dnl check for 8-bit atomic support - JE_COMPILABLE([GCC 8-bit __atomic atomics], [ - ], [ - unsigned char x = 0; - int val = 1; - int y = __atomic_fetch_add(&x, val, __ATOMIC_RELAXED); - int after_add = (int)x; - return after_add == 1; - ], [je_cv_gcc_u8_atomic_atomics]) - if test "x${je_cv_gcc_u8_atomic_atomics}" = "xyes" ; then - AC_DEFINE([JEMALLOC_GCC_U8_ATOMIC_ATOMICS]) - fi -fi - -dnl ============================================================================ -dnl Check for GCC-style __sync atomics. - -JE_COMPILABLE([GCC __sync atomics], [ -], [ - int x = 0; - int before_add = __sync_fetch_and_add(&x, 1); - int after_add = x; - return (before_add == 0) && (after_add == 1); -], [je_cv_gcc_sync_atomics]) -if test "x${je_cv_gcc_sync_atomics}" = "xyes" ; then - AC_DEFINE([JEMALLOC_GCC_SYNC_ATOMICS]) - - dnl check for 8-bit atomic support - JE_COMPILABLE([GCC 8-bit __sync atomics], [ - ], [ - unsigned char x = 0; - int before_add = __sync_fetch_and_add(&x, 1); - int after_add = (int)x; - return (before_add == 0) && (after_add == 1); - ], [je_cv_gcc_u8_sync_atomics]) - if test "x${je_cv_gcc_u8_sync_atomics}" = "xyes" ; then - AC_DEFINE([JEMALLOC_GCC_U8_SYNC_ATOMICS]) - fi -fi - -dnl ============================================================================ -dnl Check for atomic(3) operations as provided on Darwin. -dnl We need this not for the atomic operations (which are provided above), but -dnl rather for the OS_unfair_lock type it exposes. - -JE_COMPILABLE([Darwin OSAtomic*()], [ -#include <libkern/OSAtomic.h> -#include <inttypes.h> -], [ - { - int32_t x32 = 0; - volatile int32_t *x32p = &x32; - OSAtomicAdd32(1, x32p); - } - { - int64_t x64 = 0; - volatile int64_t *x64p = &x64; - OSAtomicAdd64(1, x64p); - } -], [je_cv_osatomic]) -if test "x${je_cv_osatomic}" = "xyes" ; then - AC_DEFINE([JEMALLOC_OSATOMIC], [ ]) -fi - -dnl ============================================================================ -dnl Check for madvise(2). - -JE_COMPILABLE([madvise(2)], [ -#include <sys/mman.h> -], [ - madvise((void *)0, 0, 0); -], [je_cv_madvise]) -if test "x${je_cv_madvise}" = "xyes" ; then - 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], [ ]) - elif test "x${je_cv_madvise}" = "xyes" ; then - case "${host_cpu}" in i686|x86_64) - case "${host}" in *-*-linux*) - AC_DEFINE([JEMALLOC_PURGE_MADVISE_FREE], [ ]) - AC_DEFINE([JEMALLOC_DEFINE_MADVISE_FREE], [ ]) - ;; - esac - ;; - esac - 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_DO[NT]DUMP). - JE_COMPILABLE([madvise(..., MADV_DO[[NT]]DUMP)], [ -#include <sys/mman.h> -], [ - madvise((void *)0, 0, MADV_DONTDUMP); - madvise((void *)0, 0, MADV_DODUMP); -], [je_cv_madv_dontdump]) - if test "x${je_cv_madv_dontdump}" = "xyes" ; then - AC_DEFINE([JEMALLOC_MADVISE_DONTDUMP], [ ]) - 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]) -case "${host_cpu}" in - arm*) - ;; - *) - if test "x${je_cv_thp}" = "xyes" ; then - AC_DEFINE([JEMALLOC_HAVE_MADVISE_HUGE], [ ]) - fi - ;; -esac -fi - -dnl ============================================================================ -dnl Check for __builtin_clz() and __builtin_clzl(). - -AC_CACHE_CHECK([for __builtin_clz], - [je_cv_builtin_clz], - [AC_LINK_IFELSE([AC_LANG_PROGRAM([], - [ - { - unsigned x = 0; - int y = __builtin_clz(x); - } - { - unsigned long x = 0; - int y = __builtin_clzl(x); - } - ])], - [je_cv_builtin_clz=yes], - [je_cv_builtin_clz=no])]) - -if test "x${je_cv_builtin_clz}" = "xyes" ; then - AC_DEFINE([JEMALLOC_HAVE_BUILTIN_CLZ], [ ]) -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 Darwin-related configuration. - -AC_ARG_ENABLE([zone-allocator], - [AS_HELP_STRING([--disable-zone-allocator], - [Disable zone allocator for Darwin])], -[if test "x$enable_zone_allocator" = "xno" ; then - enable_zone_allocator="0" -else - enable_zone_allocator="1" -fi -], -[if test "x${abi}" = "xmacho"; then - enable_zone_allocator="1" -fi -] -) -AC_SUBST([enable_zone_allocator]) - -if test "x${enable_zone_allocator}" = "x1" ; then - if test "x${abi}" != "xmacho"; then - AC_MSG_ERROR([--enable-zone-allocator is only supported on Darwin]) - fi - AC_DEFINE([JEMALLOC_ZONE], [ ]) -fi - -dnl ============================================================================ -dnl Use initial-exec TLS by default. -AC_ARG_ENABLE([initial-exec-tls], - [AS_HELP_STRING([--disable-initial-exec-tls], - [Disable the initial-exec tls model])], -[if test "x$enable_initial_exec_tls" = "xno" ; then - enable_initial_exec_tls="0" -else - enable_initial_exec_tls="1" -fi -], -[enable_initial_exec_tls="1"] -) -AC_SUBST([enable_initial_exec_tls]) - -if test "x${je_cv_tls_model}" = "xyes" -a \ - "x${enable_initial_exec_tls}" = "x1" ; then - AC_DEFINE([JEMALLOC_TLS_MODEL], - [__attribute__((tls_model("initial-exec")))]) -else - AC_DEFINE([JEMALLOC_TLS_MODEL], [ ]) -fi - -dnl ============================================================================ -dnl Enable background threads if possible. - -if test "x${have_pthread}" = "x1" -a "x${je_cv_os_unfair_lock}" != "xyes" ; then - AC_DEFINE([JEMALLOC_BACKGROUND_THREAD]) -fi - -dnl ============================================================================ -dnl Check for glibc malloc hooks - -JE_COMPILABLE([glibc malloc hook], [ -#include <stddef.h> - -extern void (* __free_hook)(void *ptr); -extern void *(* __malloc_hook)(size_t size); -extern void *(* __realloc_hook)(void *ptr, size_t size); -], [ - void *ptr = 0L; - if (__malloc_hook) ptr = __malloc_hook(1); - if (__realloc_hook) ptr = __realloc_hook(ptr, 2); - if (__free_hook && ptr) __free_hook(ptr); -], [je_cv_glibc_malloc_hook]) -if test "x${je_cv_glibc_malloc_hook}" = "xyes" ; then - if test "x${JEMALLOC_PREFIX}" = "x" ; then - AC_DEFINE([JEMALLOC_GLIBC_MALLOC_HOOK], [ ]) - wrap_syms="${wrap_syms} __free_hook __malloc_hook __realloc_hook" - fi -fi - -JE_COMPILABLE([glibc memalign hook], [ -#include <stddef.h> - -extern void *(* __memalign_hook)(size_t alignment, size_t size); -], [ - void *ptr = 0L; - if (__memalign_hook) ptr = __memalign_hook(16, 7); -], [je_cv_glibc_memalign_hook]) -if test "x${je_cv_glibc_memalign_hook}" = "xyes" ; then - if test "x${JEMALLOC_PREFIX}" = "x" ; then - AC_DEFINE([JEMALLOC_GLIBC_MEMALIGN_HOOK], [ ]) - wrap_syms="${wrap_syms} __memalign_hook" - fi -fi - -JE_COMPILABLE([pthreads adaptive mutexes], [ -#include <pthread.h> -], [ - pthread_mutexattr_t attr; - pthread_mutexattr_init(&attr); - pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ADAPTIVE_NP); - pthread_mutexattr_destroy(&attr); -], [je_cv_pthread_mutex_adaptive_np]) -if test "x${je_cv_pthread_mutex_adaptive_np}" = "xyes" ; then - AC_DEFINE([JEMALLOC_HAVE_PTHREAD_MUTEX_ADAPTIVE_NP], [ ]) -fi - -JE_CFLAGS_SAVE() -JE_CFLAGS_ADD([-D_GNU_SOURCE]) -JE_CFLAGS_ADD([-Werror]) -JE_CFLAGS_ADD([-herror_on_warning]) -JE_COMPILABLE([strerror_r returns char with gnu source], [ -#include <errno.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -], [ - char *buffer = (char *) malloc(100); - char *error = strerror_r(EINVAL, buffer, 100); - printf("%s\n", error); -], [je_cv_strerror_r_returns_char_with_gnu_source]) -JE_CFLAGS_RESTORE() -if test "x${je_cv_strerror_r_returns_char_with_gnu_source}" = "xyes" ; then - AC_DEFINE([JEMALLOC_STRERROR_R_RETURNS_CHAR_WITH_GNU_SOURCE], [ ]) -fi - -dnl ============================================================================ -dnl Check for typedefs, structures, and compiler characteristics. -AC_HEADER_STDBOOL - -dnl ============================================================================ -dnl Define commands that generate output files. - -AC_CONFIG_COMMANDS([include/jemalloc/internal/public_symbols.txt], [ - f="${objroot}include/jemalloc/internal/public_symbols.txt" - mkdir -p "${objroot}include/jemalloc/internal" - cp /dev/null "${f}" - for nm in `echo ${mangling_map} |tr ',' ' '` ; do - n=`echo ${nm} |tr ':' ' ' |awk '{print $[]1}'` - m=`echo ${nm} |tr ':' ' ' |awk '{print $[]2}'` - echo "${n}:${m}" >> "${f}" - dnl Remove name from public_syms so that it isn't redefined later. - public_syms=`for sym in ${public_syms}; do echo "${sym}"; done |grep -v "^${n}\$" |tr '\n' ' '` - done - for sym in ${public_syms} ; do - n="${sym}" - m="${JEMALLOC_PREFIX}${sym}" - echo "${n}:${m}" >> "${f}" - done -], [ - srcdir="${srcdir}" - objroot="${objroot}" - mangling_map="${mangling_map}" - public_syms="${public_syms}" - JEMALLOC_PREFIX="${JEMALLOC_PREFIX}" -]) -AC_CONFIG_COMMANDS([include/jemalloc/internal/private_symbols.awk], [ - f="${objroot}include/jemalloc/internal/private_symbols.awk" - mkdir -p "${objroot}include/jemalloc/internal" - export_syms=`for sym in ${public_syms}; do echo "${JEMALLOC_PREFIX}${sym}"; done; for sym in ${wrap_syms}; do echo "${sym}"; done;` - "${srcdir}/include/jemalloc/internal/private_symbols.sh" "${SYM_PREFIX}" ${export_syms} > "${objroot}include/jemalloc/internal/private_symbols.awk" -], [ - srcdir="${srcdir}" - objroot="${objroot}" - public_syms="${public_syms}" - wrap_syms="${wrap_syms}" - SYM_PREFIX="${SYM_PREFIX}" - JEMALLOC_PREFIX="${JEMALLOC_PREFIX}" -]) -AC_CONFIG_COMMANDS([include/jemalloc/internal/private_symbols_jet.awk], [ - f="${objroot}include/jemalloc/internal/private_symbols_jet.awk" - mkdir -p "${objroot}include/jemalloc/internal" - export_syms=`for sym in ${public_syms}; do echo "jet_${sym}"; done; for sym in ${wrap_syms}; do echo "${sym}"; done;` - "${srcdir}/include/jemalloc/internal/private_symbols.sh" "${SYM_PREFIX}" ${export_syms} > "${objroot}include/jemalloc/internal/private_symbols_jet.awk" -], [ - srcdir="${srcdir}" - objroot="${objroot}" - public_syms="${public_syms}" - wrap_syms="${wrap_syms}" - SYM_PREFIX="${SYM_PREFIX}" -]) -AC_CONFIG_COMMANDS([include/jemalloc/internal/public_namespace.h], [ - mkdir -p "${objroot}include/jemalloc/internal" - "${srcdir}/include/jemalloc/internal/public_namespace.sh" "${objroot}include/jemalloc/internal/public_symbols.txt" > "${objroot}include/jemalloc/internal/public_namespace.h" -], [ - srcdir="${srcdir}" - objroot="${objroot}" -]) -AC_CONFIG_COMMANDS([include/jemalloc/internal/public_unnamespace.h], [ - mkdir -p "${objroot}include/jemalloc/internal" - "${srcdir}/include/jemalloc/internal/public_unnamespace.sh" "${objroot}include/jemalloc/internal/public_symbols.txt" > "${objroot}include/jemalloc/internal/public_unnamespace.h" -], [ - srcdir="${srcdir}" - objroot="${objroot}" -]) -AC_CONFIG_COMMANDS([include/jemalloc/jemalloc_protos_jet.h], [ - mkdir -p "${objroot}include/jemalloc" - cat "${srcdir}/include/jemalloc/jemalloc_protos.h.in" | sed -e 's/@je_@/jet_/g' > "${objroot}include/jemalloc/jemalloc_protos_jet.h" -], [ - srcdir="${srcdir}" - objroot="${objroot}" -]) -AC_CONFIG_COMMANDS([include/jemalloc/jemalloc_rename.h], [ - mkdir -p "${objroot}include/jemalloc" - "${srcdir}/include/jemalloc/jemalloc_rename.sh" "${objroot}include/jemalloc/internal/public_symbols.txt" > "${objroot}include/jemalloc/jemalloc_rename.h" -], [ - srcdir="${srcdir}" - objroot="${objroot}" -]) -AC_CONFIG_COMMANDS([include/jemalloc/jemalloc_mangle.h], [ - mkdir -p "${objroot}include/jemalloc" - "${srcdir}/include/jemalloc/jemalloc_mangle.sh" "${objroot}include/jemalloc/internal/public_symbols.txt" je_ > "${objroot}include/jemalloc/jemalloc_mangle.h" -], [ - srcdir="${srcdir}" - objroot="${objroot}" -]) -AC_CONFIG_COMMANDS([include/jemalloc/jemalloc_mangle_jet.h], [ - mkdir -p "${objroot}include/jemalloc" - "${srcdir}/include/jemalloc/jemalloc_mangle.sh" "${objroot}include/jemalloc/internal/public_symbols.txt" jet_ > "${objroot}include/jemalloc/jemalloc_mangle_jet.h" -], [ - srcdir="${srcdir}" - objroot="${objroot}" -]) -AC_CONFIG_COMMANDS([include/jemalloc/jemalloc.h], [ - mkdir -p "${objroot}include/jemalloc" - "${srcdir}/include/jemalloc/jemalloc.sh" "${objroot}" > "${objroot}include/jemalloc/jemalloc${install_suffix}.h" -], [ - srcdir="${srcdir}" - objroot="${objroot}" - install_suffix="${install_suffix}" -]) - -dnl Process .in files. -AC_SUBST([cfghdrs_in]) -AC_SUBST([cfghdrs_out]) -AC_CONFIG_HEADERS([$cfghdrs_tup]) - -dnl ============================================================================ -dnl Generate outputs. - -AC_CONFIG_FILES([$cfgoutputs_tup config.stamp bin/jemalloc-config bin/jemalloc.sh bin/jeprof]) -AC_SUBST([cfgoutputs_in]) -AC_SUBST([cfgoutputs_out]) -AC_OUTPUT - -dnl ============================================================================ -dnl Print out the results of configuration. -AC_MSG_RESULT([===============================================================================]) -AC_MSG_RESULT([jemalloc version : ${jemalloc_version}]) -AC_MSG_RESULT([library revision : ${rev}]) -AC_MSG_RESULT([]) -AC_MSG_RESULT([CONFIG : ${CONFIG}]) -AC_MSG_RESULT([CC : ${CC}]) -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([CXX : ${CXX}]) -AC_MSG_RESULT([CONFIGURE_CXXFLAGS : ${CONFIGURE_CXXFLAGS}]) -AC_MSG_RESULT([SPECIFIED_CXXFLAGS : ${SPECIFIED_CXXFLAGS}]) -AC_MSG_RESULT([EXTRA_CXXFLAGS : ${EXTRA_CXXFLAGS}]) -AC_MSG_RESULT([LDFLAGS : ${LDFLAGS}]) -AC_MSG_RESULT([EXTRA_LDFLAGS : ${EXTRA_LDFLAGS}]) -AC_MSG_RESULT([DSO_LDFLAGS : ${DSO_LDFLAGS}]) -AC_MSG_RESULT([LIBS : ${LIBS}]) -AC_MSG_RESULT([RPATH_EXTRA : ${RPATH_EXTRA}]) -AC_MSG_RESULT([]) -AC_MSG_RESULT([XSLTPROC : ${XSLTPROC}]) -AC_MSG_RESULT([XSLROOT : ${XSLROOT}]) -AC_MSG_RESULT([]) -AC_MSG_RESULT([PREFIX : ${PREFIX}]) -AC_MSG_RESULT([BINDIR : ${BINDIR}]) -AC_MSG_RESULT([DATADIR : ${DATADIR}]) -AC_MSG_RESULT([INCLUDEDIR : ${INCLUDEDIR}]) -AC_MSG_RESULT([LIBDIR : ${LIBDIR}]) -AC_MSG_RESULT([MANDIR : ${MANDIR}]) -AC_MSG_RESULT([]) -AC_MSG_RESULT([srcroot : ${srcroot}]) -AC_MSG_RESULT([abs_srcroot : ${abs_srcroot}]) -AC_MSG_RESULT([objroot : ${objroot}]) -AC_MSG_RESULT([abs_objroot : ${abs_objroot}]) -AC_MSG_RESULT([]) -AC_MSG_RESULT([JEMALLOC_PREFIX : ${JEMALLOC_PREFIX}]) -AC_MSG_RESULT([JEMALLOC_PRIVATE_NAMESPACE]) -AC_MSG_RESULT([ : ${JEMALLOC_PRIVATE_NAMESPACE}]) -AC_MSG_RESULT([install_suffix : ${install_suffix}]) -AC_MSG_RESULT([malloc_conf : ${config_malloc_conf}]) -AC_MSG_RESULT([documentation : ${enable_doc}]) -AC_MSG_RESULT([shared libs : ${enable_shared}]) -AC_MSG_RESULT([static libs : ${enable_static}]) -AC_MSG_RESULT([autogen : ${enable_autogen}]) -AC_MSG_RESULT([debug : ${enable_debug}]) -AC_MSG_RESULT([stats : ${enable_stats}]) -AC_MSG_RESULT([experimetal_smallocx : ${enable_experimental_smallocx}]) -AC_MSG_RESULT([prof : ${enable_prof}]) -AC_MSG_RESULT([prof-libunwind : ${enable_prof_libunwind}]) -AC_MSG_RESULT([prof-libgcc : ${enable_prof_libgcc}]) -AC_MSG_RESULT([prof-gcc : ${enable_prof_gcc}]) -AC_MSG_RESULT([fill : ${enable_fill}]) -AC_MSG_RESULT([utrace : ${enable_utrace}]) -AC_MSG_RESULT([xmalloc : ${enable_xmalloc}]) -AC_MSG_RESULT([log : ${enable_log}]) -AC_MSG_RESULT([lazy_lock : ${enable_lazy_lock}]) -AC_MSG_RESULT([cache-oblivious : ${enable_cache_oblivious}]) -AC_MSG_RESULT([cxx : ${enable_cxx}]) -AC_MSG_RESULT([===============================================================================]) ->>>>>>> main diff --git a/contrib/jemalloc/doc/jemalloc.xml.in b/contrib/jemalloc/doc/jemalloc.xml.in index e2b15de21961..4f5d27996816 100644 --- a/contrib/jemalloc/doc/jemalloc.xml.in +++ b/contrib/jemalloc/doc/jemalloc.xml.in @@ -1,4 +1,3 @@ -<<<<<<< HEAD <?xml version='1.0' encoding='UTF-8'?> <?xml-stylesheet type="text/xsl" href="http://docbook.sourceforge.net/release/xsl/current/manpages/docbook.xsl"?> @@ -3787,3544 +3786,3 @@ malloc_conf = "narenas:1";]]></programlisting></para> 11.0.</para> </refsect1> </refentry> -||||||| dec341af7695 -======= -<?xml version='1.0' encoding='UTF-8'?> -<?xml-stylesheet type="text/xsl" - href="http://docbook.sourceforge.net/release/xsl/current/manpages/docbook.xsl"?> -<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.4//EN" - "http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd" [ -]> - -<refentry> - <refentryinfo> - <title>User Manual</title> - <productname>jemalloc</productname> - <releaseinfo role="version">@jemalloc_version@</releaseinfo> - <authorgroup> - <author> - <firstname>Jason</firstname> - <surname>Evans</surname> - <personblurb>Author</personblurb> - </author> - </authorgroup> - </refentryinfo> - <refmeta> - <refentrytitle>JEMALLOC</refentrytitle> - <manvolnum>3</manvolnum> - </refmeta> - <refnamediv> - <refdescriptor>jemalloc</refdescriptor> - <refname>jemalloc</refname> - <!-- Each refname causes a man page file to be created. Only if this were - the system malloc(3) implementation would these files be appropriate. - <refname>malloc</refname> - <refname>calloc</refname> - <refname>posix_memalign</refname> - <refname>aligned_alloc</refname> - <refname>realloc</refname> - <refname>free</refname> - <refname>mallocx</refname> - <refname>rallocx</refname> - <refname>xallocx</refname> - <refname>sallocx</refname> - <refname>dallocx</refname> - <refname>sdallocx</refname> - <refname>nallocx</refname> - <refname>mallctl</refname> - <refname>mallctlnametomib</refname> - <refname>mallctlbymib</refname> - <refname>malloc_stats_print</refname> - <refname>malloc_usable_size</refname> - --> - <refpurpose>general purpose memory allocation functions</refpurpose> - </refnamediv> - <refsect1 id="library"> - <title>LIBRARY</title> - <para>This manual describes jemalloc @jemalloc_version@. More information - can be found at the <ulink - url="http://jemalloc.net/">jemalloc website</ulink>.</para> - - <para>The following configuration options are enabled in libc's built-in - jemalloc: <option>--enable-fill</option>, - <option>--enable-lazy-lock</option>, <option>--enable-stats</option>, - <option>--enable-utrace</option>, <option>--enable-xmalloc</option>, and - <option>--with-malloc-conf=abort_conf:false</option>. - Additionally, <option>--enable-debug</option> is enabled in development - versions of FreeBSD (controlled by the - <constant>MK_MALLOC_PRODUCTION</constant> make variable).</para> - - </refsect1> - <refsynopsisdiv> - <title>SYNOPSIS</title> - <funcsynopsis> - <funcsynopsisinfo>#include <<filename class="headerfile">stdlib.h</filename>> -#include <<filename class="headerfile">malloc_np.h</filename>></funcsynopsisinfo> - <refsect2> - <title>Standard API</title> - <funcprototype> - <funcdef>void *<function>malloc</function></funcdef> - <paramdef>size_t <parameter>size</parameter></paramdef> - </funcprototype> - <funcprototype> - <funcdef>void *<function>calloc</function></funcdef> - <paramdef>size_t <parameter>number</parameter></paramdef> - <paramdef>size_t <parameter>size</parameter></paramdef> - </funcprototype> - <funcprototype> - <funcdef>int <function>posix_memalign</function></funcdef> - <paramdef>void **<parameter>ptr</parameter></paramdef> - <paramdef>size_t <parameter>alignment</parameter></paramdef> - <paramdef>size_t <parameter>size</parameter></paramdef> - </funcprototype> - <funcprototype> - <funcdef>void *<function>aligned_alloc</function></funcdef> - <paramdef>size_t <parameter>alignment</parameter></paramdef> - <paramdef>size_t <parameter>size</parameter></paramdef> - </funcprototype> - <funcprototype> - <funcdef>void *<function>realloc</function></funcdef> - <paramdef>void *<parameter>ptr</parameter></paramdef> - <paramdef>size_t <parameter>size</parameter></paramdef> - </funcprototype> - <funcprototype> - <funcdef>void <function>free</function></funcdef> - <paramdef>void *<parameter>ptr</parameter></paramdef> - </funcprototype> - </refsect2> - <refsect2> - <title>Non-standard API</title> - <funcprototype> - <funcdef>void *<function>mallocx</function></funcdef> - <paramdef>size_t <parameter>size</parameter></paramdef> - <paramdef>int <parameter>flags</parameter></paramdef> - </funcprototype> - <funcprototype> - <funcdef>void *<function>rallocx</function></funcdef> - <paramdef>void *<parameter>ptr</parameter></paramdef> - <paramdef>size_t <parameter>size</parameter></paramdef> - <paramdef>int <parameter>flags</parameter></paramdef> - </funcprototype> - <funcprototype> - <funcdef>size_t <function>xallocx</function></funcdef> - <paramdef>void *<parameter>ptr</parameter></paramdef> - <paramdef>size_t <parameter>size</parameter></paramdef> - <paramdef>size_t <parameter>extra</parameter></paramdef> - <paramdef>int <parameter>flags</parameter></paramdef> - </funcprototype> - <funcprototype> - <funcdef>size_t <function>sallocx</function></funcdef> - <paramdef>void *<parameter>ptr</parameter></paramdef> - <paramdef>int <parameter>flags</parameter></paramdef> - </funcprototype> - <funcprototype> - <funcdef>void <function>dallocx</function></funcdef> - <paramdef>void *<parameter>ptr</parameter></paramdef> - <paramdef>int <parameter>flags</parameter></paramdef> - </funcprototype> - <funcprototype> - <funcdef>void <function>sdallocx</function></funcdef> - <paramdef>void *<parameter>ptr</parameter></paramdef> - <paramdef>size_t <parameter>size</parameter></paramdef> - <paramdef>int <parameter>flags</parameter></paramdef> - </funcprototype> - <funcprototype> - <funcdef>size_t <function>nallocx</function></funcdef> - <paramdef>size_t <parameter>size</parameter></paramdef> - <paramdef>int <parameter>flags</parameter></paramdef> - </funcprototype> - <funcprototype> - <funcdef>int <function>mallctl</function></funcdef> - <paramdef>const char *<parameter>name</parameter></paramdef> - <paramdef>void *<parameter>oldp</parameter></paramdef> - <paramdef>size_t *<parameter>oldlenp</parameter></paramdef> - <paramdef>void *<parameter>newp</parameter></paramdef> - <paramdef>size_t <parameter>newlen</parameter></paramdef> - </funcprototype> - <funcprototype> - <funcdef>int <function>mallctlnametomib</function></funcdef> - <paramdef>const char *<parameter>name</parameter></paramdef> - <paramdef>size_t *<parameter>mibp</parameter></paramdef> - <paramdef>size_t *<parameter>miblenp</parameter></paramdef> - </funcprototype> - <funcprototype> - <funcdef>int <function>mallctlbymib</function></funcdef> - <paramdef>const size_t *<parameter>mib</parameter></paramdef> - <paramdef>size_t <parameter>miblen</parameter></paramdef> - <paramdef>void *<parameter>oldp</parameter></paramdef> - <paramdef>size_t *<parameter>oldlenp</parameter></paramdef> - <paramdef>void *<parameter>newp</parameter></paramdef> - <paramdef>size_t <parameter>newlen</parameter></paramdef> - </funcprototype> - <funcprototype> - <funcdef>void <function>malloc_stats_print</function></funcdef> - <paramdef>void <parameter>(*write_cb)</parameter> - <funcparams>void *, const char *</funcparams> - </paramdef> - <paramdef>void *<parameter>cbopaque</parameter></paramdef> - <paramdef>const char *<parameter>opts</parameter></paramdef> - </funcprototype> - <funcprototype> - <funcdef>size_t <function>malloc_usable_size</function></funcdef> - <paramdef>const void *<parameter>ptr</parameter></paramdef> - </funcprototype> - <funcprototype> - <funcdef>void <function>(*malloc_message)</function></funcdef> - <paramdef>void *<parameter>cbopaque</parameter></paramdef> - <paramdef>const char *<parameter>s</parameter></paramdef> - </funcprototype> - <para><type>const char *</type><varname>malloc_conf</varname>;</para> - </refsect2> - </funcsynopsis> - </refsynopsisdiv> - <refsect1 id="description"> - <title>DESCRIPTION</title> - <refsect2> - <title>Standard API</title> - - <para>The <function>malloc()</function> function allocates - <parameter>size</parameter> bytes of uninitialized memory. The allocated - space is suitably aligned (after possible pointer coercion) for storage - of any type of object.</para> - - <para>The <function>calloc()</function> function allocates - space for <parameter>number</parameter> objects, each - <parameter>size</parameter> bytes in length. The result is identical to - calling <function>malloc()</function> with an argument of - <parameter>number</parameter> * <parameter>size</parameter>, with the - exception that the allocated memory is explicitly initialized to zero - bytes.</para> - - <para>The <function>posix_memalign()</function> function - allocates <parameter>size</parameter> bytes of memory such that the - allocation's base address is a multiple of - <parameter>alignment</parameter>, and returns the allocation in the value - pointed to by <parameter>ptr</parameter>. The requested - <parameter>alignment</parameter> must be a power of 2 at least as large as - <code language="C">sizeof(<type>void *</type>)</code>.</para> - - <para>The <function>aligned_alloc()</function> function - allocates <parameter>size</parameter> bytes of memory such that the - allocation's base address is a multiple of - <parameter>alignment</parameter>. The requested - <parameter>alignment</parameter> must be a power of 2. Behavior is - undefined if <parameter>size</parameter> is not an integral multiple of - <parameter>alignment</parameter>.</para> - - <para>The <function>realloc()</function> function changes the - size of the previously allocated memory referenced by - <parameter>ptr</parameter> to <parameter>size</parameter> bytes. The - contents of the memory are unchanged up to the lesser of the new and old - sizes. If the new size is larger, the contents of the newly allocated - portion of the memory are undefined. Upon success, the memory referenced - by <parameter>ptr</parameter> is freed and a pointer to the newly - allocated memory is returned. Note that - <function>realloc()</function> may move the memory allocation, - resulting in a different return value than <parameter>ptr</parameter>. - If <parameter>ptr</parameter> is <constant>NULL</constant>, the - <function>realloc()</function> function behaves identically to - <function>malloc()</function> for the specified size.</para> - - <para>The <function>free()</function> function causes the - allocated memory referenced by <parameter>ptr</parameter> to be made - available for future allocations. If <parameter>ptr</parameter> is - <constant>NULL</constant>, no action occurs.</para> - </refsect2> - <refsect2> - <title>Non-standard API</title> - <para>The <function>mallocx()</function>, - <function>rallocx()</function>, - <function>xallocx()</function>, - <function>sallocx()</function>, - <function>dallocx()</function>, - <function>sdallocx()</function>, and - <function>nallocx()</function> functions all have a - <parameter>flags</parameter> argument that can be used to specify - options. The functions only check the options that are contextually - relevant. Use bitwise or (<code language="C">|</code>) operations to - specify one or more of the following: - <variablelist> - <varlistentry id="MALLOCX_LG_ALIGN"> - <term><constant>MALLOCX_LG_ALIGN(<parameter>la</parameter>) - </constant></term> - - <listitem><para>Align the memory allocation to start at an address - that is a multiple of <code language="C">(1 << - <parameter>la</parameter>)</code>. This macro does not validate - that <parameter>la</parameter> is within the valid - range.</para></listitem> - </varlistentry> - <varlistentry id="MALLOCX_ALIGN"> - <term><constant>MALLOCX_ALIGN(<parameter>a</parameter>) - </constant></term> - - <listitem><para>Align the memory allocation to start at an address - that is a multiple of <parameter>a</parameter>, where - <parameter>a</parameter> is a power of two. This macro does not - validate that <parameter>a</parameter> is a power of 2. - </para></listitem> - </varlistentry> - <varlistentry id="MALLOCX_ZERO"> - <term><constant>MALLOCX_ZERO</constant></term> - - <listitem><para>Initialize newly allocated memory to contain zero - bytes. In the growing reallocation case, the real size prior to - reallocation defines the boundary between untouched bytes and those - that are initialized to contain zero bytes. If this macro is - absent, newly allocated memory is uninitialized.</para></listitem> - </varlistentry> - <varlistentry id="MALLOCX_TCACHE"> - <term><constant>MALLOCX_TCACHE(<parameter>tc</parameter>) - </constant></term> - - <listitem><para>Use the thread-specific cache (tcache) specified by - the identifier <parameter>tc</parameter>, which must have been - acquired via the <link - linkend="tcache.create"><mallctl>tcache.create</mallctl></link> - mallctl. This macro does not validate that - <parameter>tc</parameter> specifies a valid - identifier.</para></listitem> - </varlistentry> - <varlistentry id="MALLOC_TCACHE_NONE"> - <term><constant>MALLOCX_TCACHE_NONE</constant></term> - - <listitem><para>Do not use a thread-specific cache (tcache). Unless - <constant>MALLOCX_TCACHE(<parameter>tc</parameter>)</constant> or - <constant>MALLOCX_TCACHE_NONE</constant> is specified, an - automatically managed tcache will be used under many circumstances. - This macro cannot be used in the same <parameter>flags</parameter> - argument as - <constant>MALLOCX_TCACHE(<parameter>tc</parameter>)</constant>.</para></listitem> - </varlistentry> - <varlistentry id="MALLOCX_ARENA"> - <term><constant>MALLOCX_ARENA(<parameter>a</parameter>) - </constant></term> - - <listitem><para>Use the arena specified by the index - <parameter>a</parameter>. This macro has no effect for regions that - were allocated via an arena other than the one specified. This - macro does not validate that <parameter>a</parameter> specifies an - arena index in the valid range.</para></listitem> - </varlistentry> - </variablelist> - </para> - - <para>The <function>mallocx()</function> function allocates at - least <parameter>size</parameter> bytes of memory, and returns a pointer - to the base address of the allocation. Behavior is undefined if - <parameter>size</parameter> is <constant>0</constant>.</para> - - <para>The <function>rallocx()</function> function resizes the - allocation at <parameter>ptr</parameter> to be at least - <parameter>size</parameter> bytes, and returns a pointer to the base - address of the resulting allocation, which may or may not have moved from - its original location. Behavior is undefined if - <parameter>size</parameter> is <constant>0</constant>.</para> - - <para>The <function>xallocx()</function> function resizes the - allocation at <parameter>ptr</parameter> in place to be at least - <parameter>size</parameter> bytes, and returns the real size of the - allocation. If <parameter>extra</parameter> is non-zero, an attempt is - made to resize the allocation to be at least <code - language="C">(<parameter>size</parameter> + - <parameter>extra</parameter>)</code> bytes, though inability to allocate - the extra byte(s) will not by itself result in failure to resize. - Behavior is undefined if <parameter>size</parameter> is - <constant>0</constant>, or if <code - language="C">(<parameter>size</parameter> + <parameter>extra</parameter> - > <constant>SIZE_T_MAX</constant>)</code>.</para> - - <para>The <function>sallocx()</function> function returns the - real size of the allocation at <parameter>ptr</parameter>.</para> - - <para>The <function>dallocx()</function> function causes the - memory referenced by <parameter>ptr</parameter> to be made available for - future allocations.</para> - - <para>The <function>sdallocx()</function> function is an - extension of <function>dallocx()</function> with a - <parameter>size</parameter> parameter to allow the caller to pass in the - allocation size as an optimization. The minimum valid input size is the - original requested size of the allocation, and the maximum valid input - size is the corresponding value returned by - <function>nallocx()</function> or - <function>sallocx()</function>.</para> - - <para>The <function>nallocx()</function> function allocates no - memory, but it performs the same size computation as the - <function>mallocx()</function> function, and returns the real - size of the allocation that would result from the equivalent - <function>mallocx()</function> function call, or - <constant>0</constant> if the inputs exceed the maximum supported size - class and/or alignment. Behavior is undefined if - <parameter>size</parameter> is <constant>0</constant>.</para> - - <para>The <function>mallctl()</function> function provides a - general interface for introspecting the memory allocator, as well as - setting modifiable parameters and triggering actions. The - period-separated <parameter>name</parameter> argument specifies a - location in a tree-structured namespace; see the <xref - linkend="mallctl_namespace" xrefstyle="template:%t"/> section for - documentation on the tree contents. To read a value, pass a pointer via - <parameter>oldp</parameter> to adequate space to contain the value, and a - pointer to its length via <parameter>oldlenp</parameter>; otherwise pass - <constant>NULL</constant> and <constant>NULL</constant>. Similarly, to - write a value, pass a pointer to the value via - <parameter>newp</parameter>, and its length via - <parameter>newlen</parameter>; otherwise pass <constant>NULL</constant> - and <constant>0</constant>.</para> - - <para>The <function>mallctlnametomib()</function> function - provides a way to avoid repeated name lookups for applications that - repeatedly query the same portion of the namespace, by translating a name - to a <quote>Management Information Base</quote> (MIB) that can be passed - repeatedly to <function>mallctlbymib()</function>. Upon - successful return from <function>mallctlnametomib()</function>, - <parameter>mibp</parameter> contains an array of - <parameter>*miblenp</parameter> integers, where - <parameter>*miblenp</parameter> is the lesser of the number of components - in <parameter>name</parameter> and the input value of - <parameter>*miblenp</parameter>. Thus it is possible to pass a - <parameter>*miblenp</parameter> that is smaller than the number of - period-separated name components, which results in a partial MIB that can - be used as the basis for constructing a complete MIB. For name - components that are integers (e.g. the 2 in - <link - linkend="arenas.bin.i.size"><mallctl>arenas.bin.2.size</mallctl></link>), - the corresponding MIB component will always be that integer. Therefore, - it is legitimate to construct code like the following: <programlisting - language="C"><![CDATA[ -unsigned nbins, i; -size_t mib[4]; -size_t len, miblen; - -len = sizeof(nbins); -mallctl("arenas.nbins", &nbins, &len, NULL, 0); - -miblen = 4; -mallctlnametomib("arenas.bin.0.size", mib, &miblen); -for (i = 0; i < nbins; i++) { - size_t bin_size; - - mib[2] = i; - len = sizeof(bin_size); - mallctlbymib(mib, miblen, (void *)&bin_size, &len, NULL, 0); - /* Do something with bin_size... */ -}]]></programlisting></para> - - <varlistentry id="malloc_stats_print_opts"> - </varlistentry> - <para>The <function>malloc_stats_print()</function> function writes - summary statistics via the <parameter>write_cb</parameter> callback - function pointer and <parameter>cbopaque</parameter> data passed to - <parameter>write_cb</parameter>, or <function>malloc_message()</function> - if <parameter>write_cb</parameter> is <constant>NULL</constant>. The - statistics are presented in human-readable form unless <quote>J</quote> is - specified as a character within the <parameter>opts</parameter> string, in - which case the statistics are presented in <ulink - 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 - <function>malloc_stats_print()</function> uses the - <function>mallctl*()</function> functions internally, so inconsistent - statistics can be reported if multiple threads use these functions - simultaneously. If <option>--enable-stats</option> is specified during - configuration, <quote>m</quote>, <quote>d</quote>, and <quote>a</quote> - can be specified to omit merged arena, destroyed merged arena, and per - arena statistics, respectively; <quote>b</quote> and <quote>l</quote> can - be specified to omit per size class statistics for bins and large objects, - respectively; <quote>x</quote> can be specified to omit all mutex - statistics; <quote>e</quote> can be used to omit extent statistics. - Unrecognized characters are silently ignored. Note that thread caching - may prevent some statistics from being completely up to date, since extra - locking would be required to merge counters that track thread cache - operations.</para> - - <para>The <function>malloc_usable_size()</function> function - returns the usable size of the allocation pointed to by - <parameter>ptr</parameter>. The return value may be larger than the size - that was requested during allocation. The - <function>malloc_usable_size()</function> function is not a - mechanism for in-place <function>realloc()</function>; rather - it is provided solely as a tool for introspection purposes. Any - discrepancy between the requested allocation size and the size reported - by <function>malloc_usable_size()</function> should not be - depended on, since such behavior is entirely implementation-dependent. - </para> - </refsect2> - </refsect1> - <refsect1 id="tuning"> - <title>TUNING</title> - <para>Once, when the first call is made to one of the memory allocation - routines, the allocator initializes its internals based in part on various - options that can be specified at compile- or run-time.</para> - - <para>The string specified via <option>--with-malloc-conf</option>, the - string pointed to by the global variable <varname>malloc_conf</varname>, the - <quote>name</quote> of the file referenced by the symbolic link named - <filename class="symlink">/etc/malloc.conf</filename>, and the value of the - environment variable <envar>MALLOC_CONF</envar>, will be interpreted, in - that order, from left to right as options. Note that - <varname>malloc_conf</varname> may be read before - <function>main()</function> is entered, so the declaration of - <varname>malloc_conf</varname> should specify an initializer that contains - the final value to be read by jemalloc. <option>--with-malloc-conf</option> - and <varname>malloc_conf</varname> are compile-time mechanisms, whereas - <filename class="symlink">/etc/malloc.conf</filename> and - <envar>MALLOC_CONF</envar> can be safely set any time prior to program - invocation.</para> - - <para>An options string is a comma-separated list of option:value pairs. - There is one key corresponding to each <link - linkend="opt.abort"><mallctl>opt.*</mallctl></link> mallctl (see the <xref - linkend="mallctl_namespace" xrefstyle="template:%t"/> section for options - documentation). For example, <literal>abort:true,narenas:1</literal> sets - the <link linkend="opt.abort"><mallctl>opt.abort</mallctl></link> and <link - linkend="opt.narenas"><mallctl>opt.narenas</mallctl></link> options. Some - options have boolean values (true/false), others have integer values (base - 8, 10, or 16, depending on prefix), and yet others have raw string - values.</para> - </refsect1> - <refsect1 id="implementation_notes"> - <title>IMPLEMENTATION NOTES</title> - <para>Traditionally, allocators have used - <citerefentry><refentrytitle>sbrk</refentrytitle> - <manvolnum>2</manvolnum></citerefentry> to obtain memory, which is - suboptimal for several reasons, including race conditions, increased - fragmentation, and artificial limitations on maximum usable memory. If - <citerefentry><refentrytitle>sbrk</refentrytitle> - <manvolnum>2</manvolnum></citerefentry> is supported by the operating - system, this allocator uses both - <citerefentry><refentrytitle>mmap</refentrytitle> - <manvolnum>2</manvolnum></citerefentry> and - <citerefentry><refentrytitle>sbrk</refentrytitle> - <manvolnum>2</manvolnum></citerefentry>, in that order of preference; - otherwise only <citerefentry><refentrytitle>mmap</refentrytitle> - <manvolnum>2</manvolnum></citerefentry> is used.</para> - - <para>This allocator uses multiple arenas in order to reduce lock - contention for threaded programs on multi-processor systems. This works - well with regard to threading scalability, but incurs some costs. There is - a small fixed per-arena overhead, and additionally, arenas manage memory - completely independently of each other, which means a small fixed increase - in overall memory fragmentation. These overheads are not generally an - issue, given the number of arenas normally used. Note that using - substantially more arenas than the default is not likely to improve - performance, mainly due to reduced cache performance. However, it may make - sense to reduce the number of arenas if an application does not make much - use of the allocation functions.</para> - - <para>In addition to multiple arenas, this allocator supports - thread-specific caching, in order to make it possible to completely avoid - synchronization for most allocation requests. Such caching allows very fast - allocation in the common case, but it increases memory usage and - fragmentation, since a bounded number of objects can remain allocated in - each thread cache.</para> - - <para>Memory is conceptually broken into extents. Extents are always - aligned to multiples of the page size. This alignment makes it possible to - find metadata for user objects quickly. User objects are broken into two - categories according to size: small and large. Contiguous small objects - comprise a slab, which resides within a single extent, whereas large objects - each have their own extents backing them.</para> - - <para>Small objects are managed in groups by slabs. Each slab maintains - a bitmap to track which regions are in use. Allocation requests that are no - more than half the quantum (8 or 16, depending on architecture) are rounded - up to the nearest power of two that is at least <code - language="C">sizeof(<type>double</type>)</code>. All other object size - classes are multiples of the quantum, spaced such that there are four size - classes for each doubling in size, which limits internal fragmentation to - approximately 20% for all but the smallest size classes. Small size classes - are smaller than four times the page size, and large size classes extend - from four times the page size up to the largest size class that does not - exceed <constant>PTRDIFF_MAX</constant>.</para> - - <para>Allocations are packed tightly together, which can be an issue for - multi-threaded applications. If you need to assure that allocations do not - suffer from cacheline sharing, round your allocation requests up to the - nearest multiple of the cacheline size, or specify cacheline alignment when - allocating.</para> - - <para>The <function>realloc()</function>, - <function>rallocx()</function>, and - <function>xallocx()</function> functions may resize allocations - without moving them under limited circumstances. Unlike the - <function>*allocx()</function> API, the standard API does not - officially round up the usable size of an allocation to the nearest size - class, so technically it is necessary to call - <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 - 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 - in-place resizing, but the current implementation also tries to resize large - allocations in place, as long as the pre-size and post-size are both large. - For shrinkage to succeed, the extent allocator must support splitting (see - <link - linkend="arena.i.extent_hooks"><mallctl>arena.<i>.extent_hooks</mallctl></link>). - Growth only succeeds if the trailing memory is currently available, and the - extent allocator supports merging.</para> - - <para>Assuming 4 KiB pages and a 16-byte quantum on a 64-bit system, the - size classes in each category are as shown in <xref linkend="size_classes" - xrefstyle="template:Table %n"/>.</para> - - <table xml:id="size_classes" frame="all"> - <title>Size classes</title> - <tgroup cols="3" colsep="1" rowsep="1"> - <colspec colname="c1" align="left"/> - <colspec colname="c2" align="right"/> - <colspec colname="c3" align="left"/> - <thead> - <row> - <entry>Category</entry> - <entry>Spacing</entry> - <entry>Size</entry> - </row> - </thead> - <tbody> - <row> - <entry morerows="8">Small</entry> - <entry>lg</entry> - <entry>[8]</entry> - </row> - <row> - <entry>16</entry> - <entry>[16, 32, 48, 64, 80, 96, 112, 128]</entry> - </row> - <row> - <entry>32</entry> - <entry>[160, 192, 224, 256]</entry> - </row> - <row> - <entry>64</entry> - <entry>[320, 384, 448, 512]</entry> - </row> - <row> - <entry>128</entry> - <entry>[640, 768, 896, 1024]</entry> - </row> - <row> - <entry>256</entry> - <entry>[1280, 1536, 1792, 2048]</entry> - </row> - <row> - <entry>512</entry> - <entry>[2560, 3072, 3584, 4096]</entry> - </row> - <row> - <entry>1 KiB</entry> - <entry>[5 KiB, 6 KiB, 7 KiB, 8 KiB]</entry> - </row> - <row> - <entry>2 KiB</entry> - <entry>[10 KiB, 12 KiB, 14 KiB]</entry> - </row> - <row> - <entry morerows="15">Large</entry> - <entry>2 KiB</entry> - <entry>[16 KiB]</entry> - </row> - <row> - <entry>4 KiB</entry> - <entry>[20 KiB, 24 KiB, 28 KiB, 32 KiB]</entry> - </row> - <row> - <entry>8 KiB</entry> - <entry>[40 KiB, 48 KiB, 54 KiB, 64 KiB]</entry> - </row> - <row> - <entry>16 KiB</entry> - <entry>[80 KiB, 96 KiB, 112 KiB, 128 KiB]</entry> - </row> - <row> - <entry>32 KiB</entry> - <entry>[160 KiB, 192 KiB, 224 KiB, 256 KiB]</entry> - </row> - <row> - <entry>64 KiB</entry> - <entry>[320 KiB, 384 KiB, 448 KiB, 512 KiB]</entry> - </row> - <row> - <entry>128 KiB</entry> - <entry>[640 KiB, 768 KiB, 896 KiB, 1 MiB]</entry> - </row> - <row> - <entry>256 KiB</entry> - <entry>[1280 KiB, 1536 KiB, 1792 KiB, 2 MiB]</entry> - </row> - <row> - <entry>512 KiB</entry> - <entry>[2560 KiB, 3 MiB, 3584 KiB, 4 MiB]</entry> - </row> - <row> - <entry>1 MiB</entry> - <entry>[5 MiB, 6 MiB, 7 MiB, 8 MiB]</entry> - </row> - <row> - <entry>2 MiB</entry> - <entry>[10 MiB, 12 MiB, 14 MiB, 16 MiB]</entry> - </row> - <row> - <entry>4 MiB</entry> - <entry>[20 MiB, 24 MiB, 28 MiB, 32 MiB]</entry> - </row> - <row> - <entry>8 MiB</entry> - <entry>[40 MiB, 48 MiB, 56 MiB, 64 MiB]</entry> - </row> - <row> - <entry>...</entry> - <entry>...</entry> - </row> - <row> - <entry>512 PiB</entry> - <entry>[2560 PiB, 3 EiB, 3584 PiB, 4 EiB]</entry> - </row> - <row> - <entry>1 EiB</entry> - <entry>[5 EiB, 6 EiB, 7 EiB]</entry> - </row> - </tbody> - </tgroup> - </table> - </refsect1> - <refsect1 id="mallctl_namespace"> - <title>MALLCTL NAMESPACE</title> - <para>The following names are defined in the namespace accessible via the - <function>mallctl*()</function> functions. Value types are specified in - parentheses, their readable/writable statuses are encoded as - <literal>rw</literal>, <literal>r-</literal>, <literal>-w</literal>, or - <literal>--</literal>, and required build configuration flags follow, if - any. A name element encoded as <literal><i></literal> or - <literal><j></literal> indicates an integer component, where the - integer varies from 0 to some upper value that must be determined via - introspection. In the case of <mallctl>stats.arenas.<i>.*</mallctl> - and <mallctl>arena.<i>.{initialized,purge,decay,dss}</mallctl>, - <literal><i></literal> equal to - <constant>MALLCTL_ARENAS_ALL</constant> can be used to operate on all arenas - or access the summation of statistics from all arenas; similarly - <literal><i></literal> equal to - <constant>MALLCTL_ARENAS_DESTROYED</constant> can be used to access the - summation of statistics from all destroyed arenas. These constants can be - utilized either via <function>mallctlnametomib()</function> followed by - <function>mallctlbymib()</function>, or via code such as the following: - <programlisting language="C"><![CDATA[ -#define STRINGIFY_HELPER(x) #x -#define STRINGIFY(x) STRINGIFY_HELPER(x) - -mallctl("arena." STRINGIFY(MALLCTL_ARENAS_ALL) ".decay", - NULL, NULL, NULL, 0);]]></programlisting> - Take special note of the <link - linkend="epoch"><mallctl>epoch</mallctl></link> mallctl, which controls - refreshing of cached dynamic statistics.</para> - - <variablelist> - <varlistentry id="version"> - <term> - <mallctl>version</mallctl> - (<type>const char *</type>) - <literal>r-</literal> - </term> - <listitem><para>Return the jemalloc version string.</para></listitem> - </varlistentry> - - <varlistentry id="epoch"> - <term> - <mallctl>epoch</mallctl> - (<type>uint64_t</type>) - <literal>rw</literal> - </term> - <listitem><para>If a value is passed in, refresh the data from which - the <function>mallctl*()</function> functions report values, - and increment the epoch. Return the current epoch. This is useful for - detecting whether another thread caused a refresh.</para></listitem> - </varlistentry> - - <varlistentry id="background_thread"> - <term> - <mallctl>background_thread</mallctl> - (<type>bool</type>) - <literal>rw</literal> - </term> - <listitem><para>Enable/disable internal background worker threads. When - set to true, background threads are created on demand (the number of - background threads will be no more than the number of CPUs or active - arenas). Threads run periodically, and handle <link - linkend="arena.i.decay">purging</link> asynchronously. When switching - off, background threads are terminated synchronously. Note that after - <citerefentry><refentrytitle>fork</refentrytitle><manvolnum>2</manvolnum></citerefentry> - function, the state in the child process will be disabled regardless - the state in parent process. See <link - linkend="stats.background_thread.num_threads"><mallctl>stats.background_thread</mallctl></link> - for related stats. <link - linkend="opt.background_thread"><mallctl>opt.background_thread</mallctl></link> - can be used to set the default option. This option is only available on - selected pthread-based platforms.</para></listitem> - </varlistentry> - - <varlistentry id="max_background_threads"> - <term> - <mallctl>max_background_threads</mallctl> - (<type>size_t</type>) - <literal>rw</literal> - </term> - <listitem><para>Maximum number of background worker threads that will - be created. This value is capped at <link - linkend="opt.max_background_threads"><mallctl>opt.max_background_threads</mallctl></link> at - startup.</para></listitem> - </varlistentry> - - <varlistentry id="config.cache_oblivious"> - <term> - <mallctl>config.cache_oblivious</mallctl> - (<type>bool</type>) - <literal>r-</literal> - </term> - <listitem><para><option>--enable-cache-oblivious</option> was specified - during build configuration.</para></listitem> - </varlistentry> - - <varlistentry id="config.debug"> - <term> - <mallctl>config.debug</mallctl> - (<type>bool</type>) - <literal>r-</literal> - </term> - <listitem><para><option>--enable-debug</option> was specified during - build configuration.</para></listitem> - </varlistentry> - - <varlistentry id="config.fill"> - <term> - <mallctl>config.fill</mallctl> - (<type>bool</type>) - <literal>r-</literal> - </term> - <listitem><para><option>--enable-fill</option> was specified during - build configuration.</para></listitem> - </varlistentry> - - <varlistentry id="config.lazy_lock"> - <term> - <mallctl>config.lazy_lock</mallctl> - (<type>bool</type>) - <literal>r-</literal> - </term> - <listitem><para><option>--enable-lazy-lock</option> was specified - during build configuration.</para></listitem> - </varlistentry> - - <varlistentry id="config.malloc_conf"> - <term> - <mallctl>config.malloc_conf</mallctl> - (<type>const char *</type>) - <literal>r-</literal> - </term> - <listitem><para>Embedded configure-time-specified run-time options - string, empty unless <option>--with-malloc-conf</option> was specified - during build configuration.</para></listitem> - </varlistentry> - - <varlistentry id="config.prof"> - <term> - <mallctl>config.prof</mallctl> - (<type>bool</type>) - <literal>r-</literal> - </term> - <listitem><para><option>--enable-prof</option> was specified during - build configuration.</para></listitem> - </varlistentry> - - <varlistentry id="config.prof_libgcc"> - <term> - <mallctl>config.prof_libgcc</mallctl> - (<type>bool</type>) - <literal>r-</literal> - </term> - <listitem><para><option>--disable-prof-libgcc</option> was not - specified during build configuration.</para></listitem> - </varlistentry> - - <varlistentry id="config.prof_libunwind"> - <term> - <mallctl>config.prof_libunwind</mallctl> - (<type>bool</type>) - <literal>r-</literal> - </term> - <listitem><para><option>--enable-prof-libunwind</option> was specified - during build configuration.</para></listitem> - </varlistentry> - - <varlistentry id="config.stats"> - <term> - <mallctl>config.stats</mallctl> - (<type>bool</type>) - <literal>r-</literal> - </term> - <listitem><para><option>--enable-stats</option> was specified during - build configuration.</para></listitem> - </varlistentry> - - - <varlistentry id="config.utrace"> - <term> - <mallctl>config.utrace</mallctl> - (<type>bool</type>) - <literal>r-</literal> - </term> - <listitem><para><option>--enable-utrace</option> was specified during - build configuration.</para></listitem> - </varlistentry> - - <varlistentry id="config.xmalloc"> - <term> - <mallctl>config.xmalloc</mallctl> - (<type>bool</type>) - <literal>r-</literal> - </term> - <listitem><para><option>--enable-xmalloc</option> was specified during - build configuration.</para></listitem> - </varlistentry> - - <varlistentry id="opt.abort"> - <term> - <mallctl>opt.abort</mallctl> - (<type>bool</type>) - <literal>r-</literal> - </term> - <listitem><para>Abort-on-warning enabled/disabled. If true, most - warnings are fatal. Note that runtime option warnings are not included - (see <link - linkend="opt.abort_conf"><mallctl>opt.abort_conf</mallctl></link> for - that). The process will call - <citerefentry><refentrytitle>abort</refentrytitle> - <manvolnum>3</manvolnum></citerefentry> in these cases. This option is - disabled by default unless <option>--enable-debug</option> is - specified during configuration, in which case it is enabled by default. - </para></listitem> - </varlistentry> - - <varlistentry id="opt.confirm_conf"> - <term> - <mallctl>opt.confirm_conf</mallctl> - (<type>bool</type>) - <literal>r-</literal> - </term> - <listitem><para>Confirm-runtime-options-when-program-starts - enabled/disabled. If true, the string specified via - <option>--with-malloc-conf</option>, the string pointed to by the - global variable <varname>malloc_conf</varname>, the <quote>name</quote> - of the file referenced by the symbolic link named - <filename class="symlink">/etc/malloc.conf</filename>, and the value of - the environment variable <envar>MALLOC_CONF</envar>, will be printed in - order. Then, each option being set will be individually printed. This - option is disabled by default.</para></listitem> - </varlistentry> - - <varlistentry id="opt.abort_conf"> - <term> - <mallctl>opt.abort_conf</mallctl> - (<type>bool</type>) - <literal>r-</literal> - </term> - <listitem><para>Abort-on-invalid-configuration enabled/disabled. If - true, invalid runtime options are fatal. The process will call - <citerefentry><refentrytitle>abort</refentrytitle> - <manvolnum>3</manvolnum></citerefentry> in these cases. This option is - disabled by default unless <option>--enable-debug</option> is - specified during configuration, in which case it is enabled by default. - </para></listitem> - </varlistentry> - - <varlistentry id="opt.metadata_thp"> - <term> - <mallctl>opt.metadata_thp</mallctl> - (<type>const char *</type>) - <literal>r-</literal> - </term> - <listitem><para>Controls whether to allow jemalloc to use transparent - huge page (THP) for internal metadata (see <link - linkend="stats.metadata">stats.metadata</link>). <quote>always</quote> - allows such usage. <quote>auto</quote> uses no THP initially, but may - begin to do so when metadata usage reaches certain level. The default - is <quote>disabled</quote>.</para></listitem> - </varlistentry> - - <varlistentry id="opt.retain"> - <term> - <mallctl>opt.retain</mallctl> - (<type>bool</type>) - <literal>r-</literal> - </term> - <listitem><para>If true, retain unused virtual memory for later reuse - rather than discarding it by calling - <citerefentry><refentrytitle>munmap</refentrytitle> - <manvolnum>2</manvolnum></citerefentry> or equivalent (see <link - linkend="stats.retained">stats.retained</link> for related details). - It also makes jemalloc use <citerefentry> - <refentrytitle>mmap</refentrytitle><manvolnum>2</manvolnum> - </citerefentry> or equivalent in a more greedy way, mapping larger - chunks in one go. This option is disabled by default unless discarding - virtual memory is known to trigger platform-specific performance - problems, namely 1) for [64-bit] Linux, which has a quirk in its virtual - memory allocation algorithm that causes semi-permanent VM map holes - under normal jemalloc operation; and 2) for [64-bit] Windows, which - disallows split / merged regions with - <parameter><constant>MEM_RELEASE</constant></parameter>. Although the - same issues may present on 32-bit platforms as well, retaining virtual - memory for 32-bit Linux and Windows is disabled by default due to the - practical possibility of address space exhaustion. </para></listitem> - </varlistentry> - - <varlistentry id="opt.dss"> - <term> - <mallctl>opt.dss</mallctl> - (<type>const char *</type>) - <literal>r-</literal> - </term> - <listitem><para>dss (<citerefentry><refentrytitle>sbrk</refentrytitle> - <manvolnum>2</manvolnum></citerefentry>) allocation precedence as - related to <citerefentry><refentrytitle>mmap</refentrytitle> - <manvolnum>2</manvolnum></citerefentry> allocation. The following - settings are supported if - <citerefentry><refentrytitle>sbrk</refentrytitle> - <manvolnum>2</manvolnum></citerefentry> is supported by the operating - system: <quote>disabled</quote>, <quote>primary</quote>, and - <quote>secondary</quote>; otherwise only <quote>disabled</quote> is - supported. The default is <quote>secondary</quote> if - <citerefentry><refentrytitle>sbrk</refentrytitle> - <manvolnum>2</manvolnum></citerefentry> is supported by the operating - system; <quote>disabled</quote> otherwise. - </para></listitem> - </varlistentry> - - <varlistentry id="opt.narenas"> - <term> - <mallctl>opt.narenas</mallctl> - (<type>unsigned</type>) - <literal>r-</literal> - </term> - <listitem><para>Maximum number of arenas to use for automatic - multiplexing of threads and arenas. The default is four times the - number of CPUs, or one if there is a single CPU.</para></listitem> - </varlistentry> - - <varlistentry id="opt.oversize_threshold"> - <term> - <mallctl>opt.oversize_threshold</mallctl> - (<type>size_t</type>) - <literal>r-</literal> - </term> - <listitem><para>The threshold in bytes of which requests are considered - oversize. Allocation requests with greater sizes are fulfilled from a - dedicated arena (automatically managed, however not within - <literal>narenas</literal>), in order to reduce fragmentation by not - mixing huge allocations with small ones. In addition, the decay API - guarantees on the extents greater than the specified threshold may be - overridden. Note that requests with arena index specified via - <constant>MALLOCX_ARENA</constant>, or threads associated with explicit - arenas will not be considered. The default threshold is 8MiB. Values - not within large size classes disables this feature.</para></listitem> - </varlistentry> - - <varlistentry id="opt.percpu_arena"> - <term> - <mallctl>opt.percpu_arena</mallctl> - (<type>const char *</type>) - <literal>r-</literal> - </term> - <listitem><para>Per CPU arena mode. Use the <quote>percpu</quote> - setting to enable this feature, which uses number of CPUs to determine - number of arenas, and bind threads to arenas dynamically based on the - CPU the thread runs on currently. <quote>phycpu</quote> setting uses - one arena per physical CPU, which means the two hyper threads on the - same CPU share one arena. Note that no runtime checking regarding the - availability of hyper threading is done at the moment. When set to - <quote>disabled</quote>, narenas and thread to arena association will - not be impacted by this option. The default is <quote>disabled</quote>. - </para></listitem> - </varlistentry> - - <varlistentry id="opt.background_thread"> - <term> - <mallctl>opt.background_thread</mallctl> - (<type>bool</type>) - <literal>r-</literal> - </term> - <listitem><para>Internal background worker threads enabled/disabled. - Because of potential circular dependencies, enabling background thread - using this option may cause crash or deadlock during initialization. For - a reliable way to use this feature, see <link - linkend="background_thread">background_thread</link> for dynamic control - options and details. This option is disabled by - default.</para></listitem> - </varlistentry> - - <varlistentry id="opt.max_background_threads"> - <term> - <mallctl>opt.max_background_threads</mallctl> - (<type>size_t</type>) - <literal>r-</literal> - </term> - <listitem><para>Maximum number of background threads that will be created - if <link linkend="background_thread">background_thread</link> is set. - Defaults to number of cpus.</para></listitem> - </varlistentry> - - <varlistentry id="opt.dirty_decay_ms"> - <term> - <mallctl>opt.dirty_decay_ms</mallctl> - (<type>ssize_t</type>) - <literal>r-</literal> - </term> - <listitem><para>Approximate time in milliseconds from the creation of a - set of unused dirty pages until an equivalent set of unused dirty pages - is purged (i.e. converted to muzzy via e.g. - <function>madvise(<parameter>...</parameter><parameter><constant>MADV_FREE</constant></parameter>)</function> - if supported by the operating system, or converted to clean otherwise) - and/or reused. Dirty pages are defined as previously having been - potentially written to by the application, and therefore consuming - physical memory, yet having no current use. The pages are incrementally - purged according to a sigmoidal decay curve that starts and ends with - zero purge rate. A decay time of 0 causes all unused dirty pages to be - purged immediately upon creation. A decay time of -1 disables purging. - The default decay time is 10 seconds. See <link - linkend="arenas.dirty_decay_ms"><mallctl>arenas.dirty_decay_ms</mallctl></link> - and <link - linkend="arena.i.dirty_decay_ms"><mallctl>arena.<i>.dirty_decay_ms</mallctl></link> - for related dynamic control options. See <link - linkend="opt.muzzy_decay_ms"><mallctl>opt.muzzy_decay_ms</mallctl></link> - for a description of muzzy pages.for a description of muzzy pages. Note - that when the <link - linkend="opt.oversize_threshold"><mallctl>oversize_threshold</mallctl></link> - feature is enabled, the arenas reserved for oversize requests may have - its own default decay settings.</para></listitem> - </varlistentry> - - <varlistentry id="opt.muzzy_decay_ms"> - <term> - <mallctl>opt.muzzy_decay_ms</mallctl> - (<type>ssize_t</type>) - <literal>r-</literal> - </term> - <listitem><para>Approximate time in milliseconds from the creation of a - set of unused muzzy pages until an equivalent set of unused muzzy pages - is purged (i.e. converted to clean) and/or reused. Muzzy pages are - defined as previously having been unused dirty pages that were - subsequently purged in a manner that left them subject to the - reclamation whims of the operating system (e.g. - <function>madvise(<parameter>...</parameter><parameter><constant>MADV_FREE</constant></parameter>)</function>), - and therefore in an indeterminate state. The pages are incrementally - purged according to a sigmoidal decay curve that starts and ends with - zero purge rate. A decay time of 0 causes all unused muzzy pages to be - purged immediately upon creation. A decay time of -1 disables purging. - The default decay time is 10 seconds. See <link - linkend="arenas.muzzy_decay_ms"><mallctl>arenas.muzzy_decay_ms</mallctl></link> - and <link - linkend="arena.i.muzzy_decay_ms"><mallctl>arena.<i>.muzzy_decay_ms</mallctl></link> - for related dynamic control options.</para></listitem> - </varlistentry> - - <varlistentry id="opt.lg_extent_max_active_fit"> - <term> - <mallctl>opt.lg_extent_max_active_fit</mallctl> - (<type>size_t</type>) - <literal>r-</literal> - </term> - <listitem><para>When reusing dirty extents, this determines the (log - base 2 of the) maximum ratio between the size of the active extent - selected (to split off from) and the size of the requested allocation. - This prevents the splitting of large active extents for smaller - allocations, which can reduce fragmentation over the long run - (especially for non-active extents). Lower value may reduce - fragmentation, at the cost of extra active extents. The default value - is 6, which gives a maximum ratio of 64 (2^6).</para></listitem> - </varlistentry> - - <varlistentry id="opt.stats_print"> - <term> - <mallctl>opt.stats_print</mallctl> - (<type>bool</type>) - <literal>r-</literal> - </term> - <listitem><para>Enable/disable statistics printing at exit. If - enabled, the <function>malloc_stats_print()</function> - function is called at program exit via an - <citerefentry><refentrytitle>atexit</refentrytitle> - <manvolnum>3</manvolnum></citerefentry> function. <link - linkend="opt.stats_print_opts"><mallctl>opt.stats_print_opts</mallctl></link> - can be combined to specify output options. If - <option>--enable-stats</option> is specified during configuration, this - has the potential to cause deadlock for a multi-threaded process that - exits while one or more threads are executing in the memory allocation - functions. Furthermore, <function>atexit()</function> may - allocate memory during application initialization and then deadlock - internally when jemalloc in turn calls - <function>atexit()</function>, so this option is not - universally usable (though the application can register its own - <function>atexit()</function> function with equivalent - functionality). Therefore, this option should only be used with care; - it is primarily intended as a performance tuning aid during application - development. This option is disabled by default.</para></listitem> - </varlistentry> - - <varlistentry id="opt.stats_print_opts"> - <term> - <mallctl>opt.stats_print_opts</mallctl> - (<type>const char *</type>) - <literal>r-</literal> - </term> - <listitem><para>Options (the <parameter>opts</parameter> string) to pass - to the <function>malloc_stats_print()</function> at exit (enabled - through <link - linkend="opt.stats_print"><mallctl>opt.stats_print</mallctl></link>). See - available options in <link - linkend="malloc_stats_print_opts"><function>malloc_stats_print()</function></link>. - Has no effect unless <link - linkend="opt.stats_print"><mallctl>opt.stats_print</mallctl></link> is - enabled. The default is <quote></quote>.</para></listitem> - </varlistentry> - - <varlistentry id="opt.junk"> - <term> - <mallctl>opt.junk</mallctl> - (<type>const char *</type>) - <literal>r-</literal> - [<option>--enable-fill</option>] - </term> - <listitem><para>Junk filling. If set to <quote>alloc</quote>, each byte - of uninitialized allocated memory will be initialized to - <literal>0xa5</literal>. If set to <quote>free</quote>, all deallocated - memory will be initialized to <literal>0x5a</literal>. If set to - <quote>true</quote>, both allocated and deallocated memory will be - initialized, and if set to <quote>false</quote>, junk filling be - disabled entirely. This is intended for debugging and will impact - performance negatively. This option is <quote>false</quote> by default - unless <option>--enable-debug</option> is specified during - configuration, in which case it is <quote>true</quote> by - default.</para></listitem> - </varlistentry> - - <varlistentry id="opt.zero"> - <term> - <mallctl>opt.zero</mallctl> - (<type>bool</type>) - <literal>r-</literal> - [<option>--enable-fill</option>] - </term> - <listitem><para>Zero filling enabled/disabled. If enabled, each byte - of uninitialized allocated memory will be initialized to 0. Note that - this initialization only happens once for each byte, so - <function>realloc()</function> and - <function>rallocx()</function> calls do not zero memory that - was previously allocated. This is intended for debugging and will - impact performance negatively. This option is disabled by default. - </para></listitem> - </varlistentry> - - <varlistentry id="opt.utrace"> - <term> - <mallctl>opt.utrace</mallctl> - (<type>bool</type>) - <literal>r-</literal> - [<option>--enable-utrace</option>] - </term> - <listitem><para>Allocation tracing based on - <citerefentry><refentrytitle>utrace</refentrytitle> - <manvolnum>2</manvolnum></citerefentry> enabled/disabled. This option - is disabled by default.</para></listitem> - </varlistentry> - - <varlistentry id="opt.xmalloc"> - <term> - <mallctl>opt.xmalloc</mallctl> - (<type>bool</type>) - <literal>r-</literal> - [<option>--enable-xmalloc</option>] - </term> - <listitem><para>Abort-on-out-of-memory enabled/disabled. If enabled, - rather than returning failure for any allocation function, display a - diagnostic message on <constant>STDERR_FILENO</constant> and cause the - program to drop core (using - <citerefentry><refentrytitle>abort</refentrytitle> - <manvolnum>3</manvolnum></citerefentry>). If an application is - designed to depend on this behavior, set the option at compile time by - including the following in the source code: - <programlisting language="C"><![CDATA[ -malloc_conf = "xmalloc:true";]]></programlisting> - This option is disabled by default.</para></listitem> - </varlistentry> - - <varlistentry id="opt.tcache"> - <term> - <mallctl>opt.tcache</mallctl> - (<type>bool</type>) - <literal>r-</literal> - </term> - <listitem><para>Thread-specific caching (tcache) enabled/disabled. When - there are multiple threads, each thread uses a tcache for objects up to - a certain size. Thread-specific caching allows many allocations to be - satisfied without performing any thread synchronization, at the cost of - increased memory use. See the <link - linkend="opt.lg_tcache_max"><mallctl>opt.lg_tcache_max</mallctl></link> - option for related tuning information. This option is enabled by - default.</para></listitem> - </varlistentry> - - <varlistentry id="opt.lg_tcache_max"> - <term> - <mallctl>opt.lg_tcache_max</mallctl> - (<type>size_t</type>) - <literal>r-</literal> - </term> - <listitem><para>Maximum size class (log base 2) to cache in the - thread-specific cache (tcache). At a minimum, all small size classes - are cached, and at a maximum all large size classes are cached. The - default maximum is 32 KiB (2^15).</para></listitem> - </varlistentry> - - <varlistentry id="opt.thp"> - <term> - <mallctl>opt.thp</mallctl> - (<type>const char *</type>) - <literal>r-</literal> - </term> - <listitem><para>Transparent hugepage (THP) mode. Settings "always", - "never" and "default" are available if THP is supported by the operating - system. The "always" setting enables transparent hugepage for all user - memory mappings with - <parameter><constant>MADV_HUGEPAGE</constant></parameter>; "never" - ensures no transparent hugepage with - <parameter><constant>MADV_NOHUGEPAGE</constant></parameter>; the default - setting "default" makes no changes. Note that: this option does not - affect THP for jemalloc internal metadata (see <link - linkend="opt.metadata_thp"><mallctl>opt.metadata_thp</mallctl></link>); - in addition, for arenas with customized <link - linkend="arena.i.extent_hooks"><mallctl>extent_hooks</mallctl></link>, - this option is bypassed as it is implemented as part of the default - extent hooks.</para></listitem> - </varlistentry> - - <varlistentry id="opt.prof"> - <term> - <mallctl>opt.prof</mallctl> - (<type>bool</type>) - <literal>r-</literal> - [<option>--enable-prof</option>] - </term> - <listitem><para>Memory profiling enabled/disabled. If enabled, profile - memory allocation activity. See the <link - linkend="opt.prof_active"><mallctl>opt.prof_active</mallctl></link> - option for on-the-fly activation/deactivation. See the <link - linkend="opt.lg_prof_sample"><mallctl>opt.lg_prof_sample</mallctl></link> - option for probabilistic sampling control. See the <link - linkend="opt.prof_accum"><mallctl>opt.prof_accum</mallctl></link> - option for control of cumulative sample reporting. See the <link - linkend="opt.lg_prof_interval"><mallctl>opt.lg_prof_interval</mallctl></link> - option for information on interval-triggered profile dumping, the <link - linkend="opt.prof_gdump"><mallctl>opt.prof_gdump</mallctl></link> - option for information on high-water-triggered profile dumping, and the - <link linkend="opt.prof_final"><mallctl>opt.prof_final</mallctl></link> - option for final profile dumping. Profile output is compatible with - the <command>jeprof</command> command, which is based on the - <command>pprof</command> that is developed as part of the <ulink - url="http://code.google.com/p/gperftools/">gperftools - package</ulink>. See <link linkend="heap_profile_format">HEAP PROFILE - FORMAT</link> for heap profile format documentation.</para></listitem> - </varlistentry> - - <varlistentry id="opt.prof_prefix"> - <term> - <mallctl>opt.prof_prefix</mallctl> - (<type>const char *</type>) - <literal>r-</literal> - [<option>--enable-prof</option>] - </term> - <listitem><para>Filename prefix for profile dumps. If the prefix is - set to the empty string, no automatic dumps will occur; this is - primarily useful for disabling the automatic final heap dump (which - also disables leak reporting, if enabled). The default prefix is - <filename>jeprof</filename>.</para></listitem> - </varlistentry> - - <varlistentry id="opt.prof_active"> - <term> - <mallctl>opt.prof_active</mallctl> - (<type>bool</type>) - <literal>r-</literal> - [<option>--enable-prof</option>] - </term> - <listitem><para>Profiling activated/deactivated. This is a secondary - control mechanism that makes it possible to start the application with - profiling enabled (see the <link - linkend="opt.prof"><mallctl>opt.prof</mallctl></link> option) but - inactive, then toggle profiling at any time during program execution - with the <link - linkend="prof.active"><mallctl>prof.active</mallctl></link> mallctl. - This option is enabled by default.</para></listitem> - </varlistentry> - - <varlistentry id="opt.prof_thread_active_init"> - <term> - <mallctl>opt.prof_thread_active_init</mallctl> - (<type>bool</type>) - <literal>r-</literal> - [<option>--enable-prof</option>] - </term> - <listitem><para>Initial setting for <link - linkend="thread.prof.active"><mallctl>thread.prof.active</mallctl></link> - in newly created threads. The initial setting for newly created threads - can also be changed during execution via the <link - linkend="prof.thread_active_init"><mallctl>prof.thread_active_init</mallctl></link> - mallctl. This option is enabled by default.</para></listitem> - </varlistentry> - - <varlistentry id="opt.lg_prof_sample"> - <term> - <mallctl>opt.lg_prof_sample</mallctl> - (<type>size_t</type>) - <literal>r-</literal> - [<option>--enable-prof</option>] - </term> - <listitem><para>Average interval (log base 2) between allocation - samples, as measured in bytes of allocation activity. Increasing the - sampling interval decreases profile fidelity, but also decreases the - computational overhead. The default sample interval is 512 KiB (2^19 - B).</para></listitem> - </varlistentry> - - <varlistentry id="opt.prof_accum"> - <term> - <mallctl>opt.prof_accum</mallctl> - (<type>bool</type>) - <literal>r-</literal> - [<option>--enable-prof</option>] - </term> - <listitem><para>Reporting of cumulative object/byte counts in profile - dumps enabled/disabled. If this option is enabled, every unique - backtrace must be stored for the duration of execution. Depending on - the application, this can impose a large memory overhead, and the - cumulative counts are not always of interest. This option is disabled - by default.</para></listitem> - </varlistentry> - - <varlistentry id="opt.lg_prof_interval"> - <term> - <mallctl>opt.lg_prof_interval</mallctl> - (<type>ssize_t</type>) - <literal>r-</literal> - [<option>--enable-prof</option>] - </term> - <listitem><para>Average interval (log base 2) between memory profile - dumps, as measured in bytes of allocation activity. The actual - interval between dumps may be sporadic because decentralized allocation - counters are used to avoid synchronization bottlenecks. Profiles are - dumped to files named according to the pattern - <filename><prefix>.<pid>.<seq>.i<iseq>.heap</filename>, - where <literal><prefix></literal> is controlled by the - <link - linkend="opt.prof_prefix"><mallctl>opt.prof_prefix</mallctl></link> - option. By default, interval-triggered profile dumping is disabled - (encoded as -1). - </para></listitem> - </varlistentry> - - <varlistentry id="opt.prof_gdump"> - <term> - <mallctl>opt.prof_gdump</mallctl> - (<type>bool</type>) - <literal>r-</literal> - [<option>--enable-prof</option>] - </term> - <listitem><para>Set the initial state of <link - linkend="prof.gdump"><mallctl>prof.gdump</mallctl></link>, which when - enabled triggers a memory profile dump every time the total virtual - memory exceeds the previous maximum. This option is disabled by - default.</para></listitem> - </varlistentry> - - <varlistentry id="opt.prof_final"> - <term> - <mallctl>opt.prof_final</mallctl> - (<type>bool</type>) - <literal>r-</literal> - [<option>--enable-prof</option>] - </term> - <listitem><para>Use an - <citerefentry><refentrytitle>atexit</refentrytitle> - <manvolnum>3</manvolnum></citerefentry> function to dump final memory - usage to a file named according to the pattern - <filename><prefix>.<pid>.<seq>.f.heap</filename>, - where <literal><prefix></literal> is controlled by the <link - linkend="opt.prof_prefix"><mallctl>opt.prof_prefix</mallctl></link> - option. Note that <function>atexit()</function> may allocate - memory during application initialization and then deadlock internally - when jemalloc in turn calls <function>atexit()</function>, so - this option is not universally usable (though the application can - register its own <function>atexit()</function> function with - equivalent functionality). This option is disabled by - default.</para></listitem> - </varlistentry> - - <varlistentry id="opt.prof_leak"> - <term> - <mallctl>opt.prof_leak</mallctl> - (<type>bool</type>) - <literal>r-</literal> - [<option>--enable-prof</option>] - </term> - <listitem><para>Leak reporting enabled/disabled. If enabled, use an - <citerefentry><refentrytitle>atexit</refentrytitle> - <manvolnum>3</manvolnum></citerefentry> function to report memory leaks - detected by allocation sampling. See the - <link linkend="opt.prof"><mallctl>opt.prof</mallctl></link> option for - information on analyzing heap profile output. This option is disabled - by default.</para></listitem> - </varlistentry> - - <varlistentry id="thread.arena"> - <term> - <mallctl>thread.arena</mallctl> - (<type>unsigned</type>) - <literal>rw</literal> - </term> - <listitem><para>Get or set the arena associated with the calling - thread. If the specified arena was not initialized beforehand (see the - <link - linkend="arena.i.initialized"><mallctl>arena.i.initialized</mallctl></link> - mallctl), it will be automatically initialized as a side effect of - calling this interface.</para></listitem> - </varlistentry> - - <varlistentry id="thread.allocated"> - <term> - <mallctl>thread.allocated</mallctl> - (<type>uint64_t</type>) - <literal>r-</literal> - [<option>--enable-stats</option>] - </term> - <listitem><para>Get the total number of bytes ever allocated by the - calling thread. This counter has the potential to wrap around; it is - up to the application to appropriately interpret the counter in such - cases.</para></listitem> - </varlistentry> - - <varlistentry id="thread.allocatedp"> - <term> - <mallctl>thread.allocatedp</mallctl> - (<type>uint64_t *</type>) - <literal>r-</literal> - [<option>--enable-stats</option>] - </term> - <listitem><para>Get a pointer to the the value that is returned by the - <link - linkend="thread.allocated"><mallctl>thread.allocated</mallctl></link> - mallctl. This is useful for avoiding the overhead of repeated - <function>mallctl*()</function> calls.</para></listitem> - </varlistentry> - - <varlistentry id="thread.deallocated"> - <term> - <mallctl>thread.deallocated</mallctl> - (<type>uint64_t</type>) - <literal>r-</literal> - [<option>--enable-stats</option>] - </term> - <listitem><para>Get the total number of bytes ever deallocated by the - calling thread. This counter has the potential to wrap around; it is - up to the application to appropriately interpret the counter in such - cases.</para></listitem> - </varlistentry> - - <varlistentry id="thread.deallocatedp"> - <term> - <mallctl>thread.deallocatedp</mallctl> - (<type>uint64_t *</type>) - <literal>r-</literal> - [<option>--enable-stats</option>] - </term> - <listitem><para>Get a pointer to the the value that is returned by the - <link - linkend="thread.deallocated"><mallctl>thread.deallocated</mallctl></link> - mallctl. This is useful for avoiding the overhead of repeated - <function>mallctl*()</function> calls.</para></listitem> - </varlistentry> - - <varlistentry id="thread.tcache.enabled"> - <term> - <mallctl>thread.tcache.enabled</mallctl> - (<type>bool</type>) - <literal>rw</literal> - </term> - <listitem><para>Enable/disable calling thread's tcache. The tcache is - implicitly flushed as a side effect of becoming - disabled (see <link - linkend="thread.tcache.flush"><mallctl>thread.tcache.flush</mallctl></link>). - </para></listitem> - </varlistentry> - - <varlistentry id="thread.tcache.flush"> - <term> - <mallctl>thread.tcache.flush</mallctl> - (<type>void</type>) - <literal>--</literal> - </term> - <listitem><para>Flush calling thread's thread-specific cache (tcache). - This interface releases all cached objects and internal data structures - associated with the calling thread's tcache. Ordinarily, this interface - need not be called, since automatic periodic incremental garbage - collection occurs, and the thread cache is automatically discarded when - a thread exits. However, garbage collection is triggered by allocation - activity, so it is possible for a thread that stops - allocating/deallocating to retain its cache indefinitely, in which case - the developer may find manual flushing useful.</para></listitem> - </varlistentry> - - <varlistentry id="thread.prof.name"> - <term> - <mallctl>thread.prof.name</mallctl> - (<type>const char *</type>) - <literal>r-</literal> or - <literal>-w</literal> - [<option>--enable-prof</option>] - </term> - <listitem><para>Get/set the descriptive name associated with the calling - thread in memory profile dumps. An internal copy of the name string is - created, so the input string need not be maintained after this interface - completes execution. The output string of this interface should be - copied for non-ephemeral uses, because multiple implementation details - can cause asynchronous string deallocation. Furthermore, each - invocation of this interface can only read or write; simultaneous - read/write is not supported due to string lifetime limitations. The - name string must be nil-terminated and comprised only of characters in - the sets recognized - by <citerefentry><refentrytitle>isgraph</refentrytitle> - <manvolnum>3</manvolnum></citerefentry> and - <citerefentry><refentrytitle>isblank</refentrytitle> - <manvolnum>3</manvolnum></citerefentry>.</para></listitem> - </varlistentry> - - <varlistentry id="thread.prof.active"> - <term> - <mallctl>thread.prof.active</mallctl> - (<type>bool</type>) - <literal>rw</literal> - [<option>--enable-prof</option>] - </term> - <listitem><para>Control whether sampling is currently active for the - calling thread. This is an activation mechanism in addition to <link - linkend="prof.active"><mallctl>prof.active</mallctl></link>; both must - be active for the calling thread to sample. This flag is enabled by - default.</para></listitem> - </varlistentry> - - <varlistentry id="tcache.create"> - <term> - <mallctl>tcache.create</mallctl> - (<type>unsigned</type>) - <literal>r-</literal> - </term> - <listitem><para>Create an explicit thread-specific cache (tcache) and - return an identifier that can be passed to the <link - linkend="MALLOCX_TCACHE"><constant>MALLOCX_TCACHE(<parameter>tc</parameter>)</constant></link> - macro to explicitly use the specified cache rather than the - automatically managed one that is used by default. Each explicit cache - can be used by only one thread at a time; the application must assure - that this constraint holds. - </para></listitem> - </varlistentry> - - <varlistentry id="tcache.flush"> - <term> - <mallctl>tcache.flush</mallctl> - (<type>unsigned</type>) - <literal>-w</literal> - </term> - <listitem><para>Flush the specified thread-specific cache (tcache). The - same considerations apply to this interface as to <link - linkend="thread.tcache.flush"><mallctl>thread.tcache.flush</mallctl></link>, - except that the tcache will never be automatically discarded. - </para></listitem> - </varlistentry> - - <varlistentry id="tcache.destroy"> - <term> - <mallctl>tcache.destroy</mallctl> - (<type>unsigned</type>) - <literal>-w</literal> - </term> - <listitem><para>Flush the specified thread-specific cache (tcache) and - make the identifier available for use during a future tcache creation. - </para></listitem> - </varlistentry> - - <varlistentry id="arena.i.initialized"> - <term> - <mallctl>arena.<i>.initialized</mallctl> - (<type>bool</type>) - <literal>r-</literal> - </term> - <listitem><para>Get whether the specified arena's statistics are - initialized (i.e. the arena was initialized prior to the current epoch). - This interface can also be nominally used to query whether the merged - statistics corresponding to <constant>MALLCTL_ARENAS_ALL</constant> are - initialized (always true).</para></listitem> - </varlistentry> - - <varlistentry id="arena.i.decay"> - <term> - <mallctl>arena.<i>.decay</mallctl> - (<type>void</type>) - <literal>--</literal> - </term> - <listitem><para>Trigger decay-based purging of unused dirty/muzzy pages - for arena <i>, or for all arenas if <i> equals - <constant>MALLCTL_ARENAS_ALL</constant>. The proportion of unused - dirty/muzzy pages to be purged depends on the current time; see <link - linkend="opt.dirty_decay_ms"><mallctl>opt.dirty_decay_ms</mallctl></link> - and <link - linkend="opt.muzzy_decay_ms"><mallctl>opt.muzy_decay_ms</mallctl></link> - for details.</para></listitem> - </varlistentry> - - <varlistentry id="arena.i.purge"> - <term> - <mallctl>arena.<i>.purge</mallctl> - (<type>void</type>) - <literal>--</literal> - </term> - <listitem><para>Purge all unused dirty pages for arena <i>, or for - all arenas if <i> equals <constant>MALLCTL_ARENAS_ALL</constant>. - </para></listitem> - </varlistentry> - - <varlistentry id="arena.i.reset"> - <term> - <mallctl>arena.<i>.reset</mallctl> - (<type>void</type>) - <literal>--</literal> - </term> - <listitem><para>Discard all of the arena's extant allocations. This - interface can only be used with arenas explicitly created via <link - linkend="arenas.create"><mallctl>arenas.create</mallctl></link>. None - of the arena's discarded/cached allocations may accessed afterward. As - part of this requirement, all thread caches which were used to - allocate/deallocate in conjunction with the arena must be flushed - beforehand.</para></listitem> - </varlistentry> - - <varlistentry id="arena.i.destroy"> - <term> - <mallctl>arena.<i>.destroy</mallctl> - (<type>void</type>) - <literal>--</literal> - </term> - <listitem><para>Destroy the arena. Discard all of the arena's extant - allocations using the same mechanism as for <link - linkend="arena.i.reset"><mallctl>arena.<i>.reset</mallctl></link> - (with all the same constraints and side effects), merge the arena stats - into those accessible at arena index - <constant>MALLCTL_ARENAS_DESTROYED</constant>, and then completely - discard all metadata associated with the arena. Future calls to <link - linkend="arenas.create"><mallctl>arenas.create</mallctl></link> may - recycle the arena index. Destruction will fail if any threads are - currently associated with the arena as a result of calls to <link - linkend="thread.arena"><mallctl>thread.arena</mallctl></link>.</para></listitem> - </varlistentry> - - <varlistentry id="arena.i.dss"> - <term> - <mallctl>arena.<i>.dss</mallctl> - (<type>const char *</type>) - <literal>rw</literal> - </term> - <listitem><para>Set the precedence of dss allocation as related to mmap - allocation for arena <i>, or for all arenas if <i> equals - <constant>MALLCTL_ARENAS_ALL</constant>. See <link - linkend="opt.dss"><mallctl>opt.dss</mallctl></link> for supported - settings.</para></listitem> - </varlistentry> - - <varlistentry id="arena.i.dirty_decay_ms"> - <term> - <mallctl>arena.<i>.dirty_decay_ms</mallctl> - (<type>ssize_t</type>) - <literal>rw</literal> - </term> - <listitem><para>Current per-arena approximate time in milliseconds from - the creation of a set of unused dirty pages until an equivalent set of - unused dirty pages is purged and/or reused. Each time this interface is - set, all currently unused dirty pages are considered to have fully - decayed, which causes immediate purging of all unused dirty pages unless - the decay time is set to -1 (i.e. purging disabled). See <link - linkend="opt.dirty_decay_ms"><mallctl>opt.dirty_decay_ms</mallctl></link> - for additional information.</para></listitem> - </varlistentry> - - <varlistentry id="arena.i.muzzy_decay_ms"> - <term> - <mallctl>arena.<i>.muzzy_decay_ms</mallctl> - (<type>ssize_t</type>) - <literal>rw</literal> - </term> - <listitem><para>Current per-arena approximate time in milliseconds from - the creation of a set of unused muzzy pages until an equivalent set of - unused muzzy pages is purged and/or reused. Each time this interface is - set, all currently unused muzzy pages are considered to have fully - decayed, which causes immediate purging of all unused muzzy pages unless - the decay time is set to -1 (i.e. purging disabled). See <link - linkend="opt.muzzy_decay_ms"><mallctl>opt.muzzy_decay_ms</mallctl></link> - for additional information.</para></listitem> - </varlistentry> - - <varlistentry id="arena.i.retain_grow_limit"> - <term> - <mallctl>arena.<i>.retain_grow_limit</mallctl> - (<type>size_t</type>) - <literal>rw</literal> - </term> - <listitem><para>Maximum size to grow retained region (only relevant when - <link linkend="opt.retain"><mallctl>opt.retain</mallctl></link> is - enabled). This controls the maximum increment to expand virtual memory, - or allocation through <link - linkend="arena.i.extent_hooks"><mallctl>arena.<i>extent_hooks</mallctl></link>. - In particular, if customized extent hooks reserve physical memory - (e.g. 1G huge pages), this is useful to control the allocation hook's - input size. The default is no limit.</para></listitem> - </varlistentry> - - <varlistentry id="arena.i.extent_hooks"> - <term> - <mallctl>arena.<i>.extent_hooks</mallctl> - (<type>extent_hooks_t *</type>) - <literal>rw</literal> - </term> - <listitem><para>Get or set the extent management hook functions for - arena <i>. The functions must be capable of operating on all - extant extents associated with arena <i>, usually by passing - unknown extents to the replaced functions. In practice, it is feasible - to control allocation for arenas explicitly created via <link - linkend="arenas.create"><mallctl>arenas.create</mallctl></link> such - that all extents originate from an application-supplied extent allocator - (by specifying the custom extent hook functions during arena creation). - However, the API guarantees for the automatically created arenas may be - relaxed -- hooks set there may be called in a "best effort" fashion; in - addition there may be extents created prior to the application having an - opportunity to take over extent allocation.</para> - - <programlisting language="C"><![CDATA[ -typedef extent_hooks_s extent_hooks_t; -struct extent_hooks_s { - extent_alloc_t *alloc; - extent_dalloc_t *dalloc; - extent_destroy_t *destroy; - extent_commit_t *commit; - extent_decommit_t *decommit; - extent_purge_t *purge_lazy; - extent_purge_t *purge_forced; - extent_split_t *split; - extent_merge_t *merge; -};]]></programlisting> - <para>The <type>extent_hooks_t</type> structure comprises function - pointers which are described individually below. jemalloc uses these - functions to manage extent lifetime, which starts off with allocation of - mapped committed memory, in the simplest case followed by deallocation. - However, there are performance and platform reasons to retain extents - for later reuse. Cleanup attempts cascade from deallocation to decommit - to forced purging to lazy purging, which gives the extent management - functions opportunities to reject the most permanent cleanup operations - in favor of less permanent (and often less costly) operations. All - operations except allocation can be universally opted out of by setting - the hook pointers to <constant>NULL</constant>, or selectively opted out - of by returning failure. Note that once the extent hook is set, the - structure is accessed directly by the associated arenas, so it must - remain valid for the entire lifetime of the arenas.</para> - - <funcsynopsis><funcprototype> - <funcdef>typedef void *<function>(extent_alloc_t)</function></funcdef> - <paramdef>extent_hooks_t *<parameter>extent_hooks</parameter></paramdef> - <paramdef>void *<parameter>new_addr</parameter></paramdef> - <paramdef>size_t <parameter>size</parameter></paramdef> - <paramdef>size_t <parameter>alignment</parameter></paramdef> - <paramdef>bool *<parameter>zero</parameter></paramdef> - <paramdef>bool *<parameter>commit</parameter></paramdef> - <paramdef>unsigned <parameter>arena_ind</parameter></paramdef> - </funcprototype></funcsynopsis> - <literallayout></literallayout> - <para>An extent allocation function conforms to the - <type>extent_alloc_t</type> type and upon success returns a pointer to - <parameter>size</parameter> bytes of mapped memory on behalf of arena - <parameter>arena_ind</parameter> such that the extent's base address is - a multiple of <parameter>alignment</parameter>, as well as setting - <parameter>*zero</parameter> to indicate whether the extent is zeroed - and <parameter>*commit</parameter> to indicate whether the extent is - committed. Upon error the function returns <constant>NULL</constant> - and leaves <parameter>*zero</parameter> and - <parameter>*commit</parameter> unmodified. The - <parameter>size</parameter> parameter is always a multiple of the page - size. The <parameter>alignment</parameter> parameter is always a power - of two at least as large as the page size. Zeroing is mandatory if - <parameter>*zero</parameter> is true upon function entry. Committing is - mandatory if <parameter>*commit</parameter> is true upon function entry. - If <parameter>new_addr</parameter> is not <constant>NULL</constant>, the - returned pointer must be <parameter>new_addr</parameter> on success or - <constant>NULL</constant> on error. Committed memory may be committed - in absolute terms as on a system that does not overcommit, or in - implicit terms as on a system that overcommits and satisfies physical - memory needs on demand via soft page faults. Note that replacing the - default extent allocation function makes the arena's <link - linkend="arena.i.dss"><mallctl>arena.<i>.dss</mallctl></link> - setting irrelevant.</para> - - <funcsynopsis><funcprototype> - <funcdef>typedef bool <function>(extent_dalloc_t)</function></funcdef> - <paramdef>extent_hooks_t *<parameter>extent_hooks</parameter></paramdef> - <paramdef>void *<parameter>addr</parameter></paramdef> - <paramdef>size_t <parameter>size</parameter></paramdef> - <paramdef>bool <parameter>committed</parameter></paramdef> - <paramdef>unsigned <parameter>arena_ind</parameter></paramdef> - </funcprototype></funcsynopsis> - <literallayout></literallayout> - <para> - An extent deallocation function conforms to the - <type>extent_dalloc_t</type> type and deallocates an extent at given - <parameter>addr</parameter> and <parameter>size</parameter> with - <parameter>committed</parameter>/decommited memory as indicated, on - behalf of arena <parameter>arena_ind</parameter>, returning false upon - success. If the function returns true, this indicates opt-out from - deallocation; the virtual memory mapping associated with the extent - remains mapped, in the same commit state, and available for future use, - in which case it will be automatically retained for later reuse.</para> - - <funcsynopsis><funcprototype> - <funcdef>typedef void <function>(extent_destroy_t)</function></funcdef> - <paramdef>extent_hooks_t *<parameter>extent_hooks</parameter></paramdef> - <paramdef>void *<parameter>addr</parameter></paramdef> - <paramdef>size_t <parameter>size</parameter></paramdef> - <paramdef>bool <parameter>committed</parameter></paramdef> - <paramdef>unsigned <parameter>arena_ind</parameter></paramdef> - </funcprototype></funcsynopsis> - <literallayout></literallayout> - <para> - An extent destruction function conforms to the - <type>extent_destroy_t</type> type and unconditionally destroys an - extent at given <parameter>addr</parameter> and - <parameter>size</parameter> with - <parameter>committed</parameter>/decommited memory as indicated, on - behalf of arena <parameter>arena_ind</parameter>. This function may be - called to destroy retained extents during arena destruction (see <link - linkend="arena.i.destroy"><mallctl>arena.<i>.destroy</mallctl></link>).</para> - - <funcsynopsis><funcprototype> - <funcdef>typedef bool <function>(extent_commit_t)</function></funcdef> - <paramdef>extent_hooks_t *<parameter>extent_hooks</parameter></paramdef> - <paramdef>void *<parameter>addr</parameter></paramdef> - <paramdef>size_t <parameter>size</parameter></paramdef> - <paramdef>size_t <parameter>offset</parameter></paramdef> - <paramdef>size_t <parameter>length</parameter></paramdef> - <paramdef>unsigned <parameter>arena_ind</parameter></paramdef> - </funcprototype></funcsynopsis> - <literallayout></literallayout> - <para>An extent commit function conforms to the - <type>extent_commit_t</type> type and commits zeroed physical memory to - back pages within an extent at given <parameter>addr</parameter> and - <parameter>size</parameter> at <parameter>offset</parameter> bytes, - extending for <parameter>length</parameter> on behalf of arena - <parameter>arena_ind</parameter>, returning false upon success. - Committed memory may be committed in absolute terms as on a system that - does not overcommit, or in implicit terms as on a system that - overcommits and satisfies physical memory needs on demand via soft page - faults. If the function returns true, this indicates insufficient - physical memory to satisfy the request.</para> - - <funcsynopsis><funcprototype> - <funcdef>typedef bool <function>(extent_decommit_t)</function></funcdef> - <paramdef>extent_hooks_t *<parameter>extent_hooks</parameter></paramdef> - <paramdef>void *<parameter>addr</parameter></paramdef> - <paramdef>size_t <parameter>size</parameter></paramdef> - <paramdef>size_t <parameter>offset</parameter></paramdef> - <paramdef>size_t <parameter>length</parameter></paramdef> - <paramdef>unsigned <parameter>arena_ind</parameter></paramdef> - </funcprototype></funcsynopsis> - <literallayout></literallayout> - <para>An extent decommit function conforms to the - <type>extent_decommit_t</type> type and decommits any physical memory - that is backing pages within an extent at given - <parameter>addr</parameter> and <parameter>size</parameter> at - <parameter>offset</parameter> bytes, extending for - <parameter>length</parameter> on behalf of arena - <parameter>arena_ind</parameter>, returning false upon success, in which - case the pages will be committed via the extent commit function before - being reused. If the function returns true, this indicates opt-out from - decommit; the memory remains committed and available for future use, in - which case it will be automatically retained for later reuse.</para> - - <funcsynopsis><funcprototype> - <funcdef>typedef bool <function>(extent_purge_t)</function></funcdef> - <paramdef>extent_hooks_t *<parameter>extent_hooks</parameter></paramdef> - <paramdef>void *<parameter>addr</parameter></paramdef> - <paramdef>size_t <parameter>size</parameter></paramdef> - <paramdef>size_t <parameter>offset</parameter></paramdef> - <paramdef>size_t <parameter>length</parameter></paramdef> - <paramdef>unsigned <parameter>arena_ind</parameter></paramdef> - </funcprototype></funcsynopsis> - <literallayout></literallayout> - <para>An extent purge function conforms to the - <type>extent_purge_t</type> type and discards physical pages - within the virtual memory mapping associated with an extent at given - <parameter>addr</parameter> and <parameter>size</parameter> at - <parameter>offset</parameter> bytes, extending for - <parameter>length</parameter> on behalf of arena - <parameter>arena_ind</parameter>. A lazy extent purge function (e.g. - implemented via - <function>madvise(<parameter>...</parameter><parameter><constant>MADV_FREE</constant></parameter>)</function>) - can delay purging indefinitely and leave the pages within the purged - virtual memory range in an indeterminite state, whereas a forced extent - purge function immediately purges, and the pages within the virtual - memory range will be zero-filled the next time they are accessed. If - the function returns true, this indicates failure to purge.</para> - - <funcsynopsis><funcprototype> - <funcdef>typedef bool <function>(extent_split_t)</function></funcdef> - <paramdef>extent_hooks_t *<parameter>extent_hooks</parameter></paramdef> - <paramdef>void *<parameter>addr</parameter></paramdef> - <paramdef>size_t <parameter>size</parameter></paramdef> - <paramdef>size_t <parameter>size_a</parameter></paramdef> - <paramdef>size_t <parameter>size_b</parameter></paramdef> - <paramdef>bool <parameter>committed</parameter></paramdef> - <paramdef>unsigned <parameter>arena_ind</parameter></paramdef> - </funcprototype></funcsynopsis> - <literallayout></literallayout> - <para>An extent split function conforms to the - <type>extent_split_t</type> type and optionally splits an extent at - given <parameter>addr</parameter> and <parameter>size</parameter> into - two adjacent extents, the first of <parameter>size_a</parameter> bytes, - and the second of <parameter>size_b</parameter> bytes, operating on - <parameter>committed</parameter>/decommitted memory as indicated, on - behalf of arena <parameter>arena_ind</parameter>, returning false upon - success. If the function returns true, this indicates that the extent - remains unsplit and therefore should continue to be operated on as a - whole.</para> - - <funcsynopsis><funcprototype> - <funcdef>typedef bool <function>(extent_merge_t)</function></funcdef> - <paramdef>extent_hooks_t *<parameter>extent_hooks</parameter></paramdef> - <paramdef>void *<parameter>addr_a</parameter></paramdef> - <paramdef>size_t <parameter>size_a</parameter></paramdef> - <paramdef>void *<parameter>addr_b</parameter></paramdef> - <paramdef>size_t <parameter>size_b</parameter></paramdef> - <paramdef>bool <parameter>committed</parameter></paramdef> - <paramdef>unsigned <parameter>arena_ind</parameter></paramdef> - </funcprototype></funcsynopsis> - <literallayout></literallayout> - <para>An extent merge function conforms to the - <type>extent_merge_t</type> type and optionally merges adjacent extents, - at given <parameter>addr_a</parameter> and <parameter>size_a</parameter> - with given <parameter>addr_b</parameter> and - <parameter>size_b</parameter> into one contiguous extent, operating on - <parameter>committed</parameter>/decommitted memory as indicated, on - behalf of arena <parameter>arena_ind</parameter>, returning false upon - success. If the function returns true, this indicates that the extents - remain distinct mappings and therefore should continue to be operated on - independently.</para> - </listitem> - </varlistentry> - - <varlistentry id="arenas.narenas"> - <term> - <mallctl>arenas.narenas</mallctl> - (<type>unsigned</type>) - <literal>r-</literal> - </term> - <listitem><para>Current limit on number of arenas.</para></listitem> - </varlistentry> - - <varlistentry id="arenas.dirty_decay_ms"> - <term> - <mallctl>arenas.dirty_decay_ms</mallctl> - (<type>ssize_t</type>) - <literal>rw</literal> - </term> - <listitem><para>Current default per-arena approximate time in - milliseconds from the creation of a set of unused dirty pages until an - equivalent set of unused dirty pages is purged and/or reused, used to - initialize <link - linkend="arena.i.dirty_decay_ms"><mallctl>arena.<i>.dirty_decay_ms</mallctl></link> - during arena creation. See <link - linkend="opt.dirty_decay_ms"><mallctl>opt.dirty_decay_ms</mallctl></link> - for additional information.</para></listitem> - </varlistentry> - - <varlistentry id="arenas.muzzy_decay_ms"> - <term> - <mallctl>arenas.muzzy_decay_ms</mallctl> - (<type>ssize_t</type>) - <literal>rw</literal> - </term> - <listitem><para>Current default per-arena approximate time in - milliseconds from the creation of a set of unused muzzy pages until an - equivalent set of unused muzzy pages is purged and/or reused, used to - initialize <link - linkend="arena.i.muzzy_decay_ms"><mallctl>arena.<i>.muzzy_decay_ms</mallctl></link> - during arena creation. See <link - linkend="opt.muzzy_decay_ms"><mallctl>opt.muzzy_decay_ms</mallctl></link> - for additional information.</para></listitem> - </varlistentry> - - <varlistentry id="arenas.quantum"> - <term> - <mallctl>arenas.quantum</mallctl> - (<type>size_t</type>) - <literal>r-</literal> - </term> - <listitem><para>Quantum size.</para></listitem> - </varlistentry> - - <varlistentry id="arenas.page"> - <term> - <mallctl>arenas.page</mallctl> - (<type>size_t</type>) - <literal>r-</literal> - </term> - <listitem><para>Page size.</para></listitem> - </varlistentry> - - <varlistentry id="arenas.tcache_max"> - <term> - <mallctl>arenas.tcache_max</mallctl> - (<type>size_t</type>) - <literal>r-</literal> - </term> - <listitem><para>Maximum thread-cached size class.</para></listitem> - </varlistentry> - - <varlistentry id="arenas.nbins"> - <term> - <mallctl>arenas.nbins</mallctl> - (<type>unsigned</type>) - <literal>r-</literal> - </term> - <listitem><para>Number of bin size classes.</para></listitem> - </varlistentry> - - <varlistentry id="arenas.nhbins"> - <term> - <mallctl>arenas.nhbins</mallctl> - (<type>unsigned</type>) - <literal>r-</literal> - </term> - <listitem><para>Total number of thread cache bin size - classes.</para></listitem> - </varlistentry> - - <varlistentry id="arenas.bin.i.size"> - <term> - <mallctl>arenas.bin.<i>.size</mallctl> - (<type>size_t</type>) - <literal>r-</literal> - </term> - <listitem><para>Maximum size supported by size class.</para></listitem> - </varlistentry> - - <varlistentry id="arenas.bin.i.nregs"> - <term> - <mallctl>arenas.bin.<i>.nregs</mallctl> - (<type>uint32_t</type>) - <literal>r-</literal> - </term> - <listitem><para>Number of regions per slab.</para></listitem> - </varlistentry> - - <varlistentry id="arenas.bin.i.slab_size"> - <term> - <mallctl>arenas.bin.<i>.slab_size</mallctl> - (<type>size_t</type>) - <literal>r-</literal> - </term> - <listitem><para>Number of bytes per slab.</para></listitem> - </varlistentry> - - <varlistentry id="arenas.nlextents"> - <term> - <mallctl>arenas.nlextents</mallctl> - (<type>unsigned</type>) - <literal>r-</literal> - </term> - <listitem><para>Total number of large size classes.</para></listitem> - </varlistentry> - - <varlistentry id="arenas.lextent.i.size"> - <term> - <mallctl>arenas.lextent.<i>.size</mallctl> - (<type>size_t</type>) - <literal>r-</literal> - </term> - <listitem><para>Maximum size supported by this large size - class.</para></listitem> - </varlistentry> - - <varlistentry id="arenas.create"> - <term> - <mallctl>arenas.create</mallctl> - (<type>unsigned</type>, <type>extent_hooks_t *</type>) - <literal>rw</literal> - </term> - <listitem><para>Explicitly create a new arena outside the range of - automatically managed arenas, with optionally specified extent hooks, - and return the new arena index.</para></listitem> - </varlistentry> - - <varlistentry id="arenas.lookup"> - <term> - <mallctl>arenas.lookup</mallctl> - (<type>unsigned</type>, <type>void*</type>) - <literal>rw</literal> - </term> - <listitem><para>Index of the arena to which an allocation belongs to.</para></listitem> - </varlistentry> - - <varlistentry id="prof.thread_active_init"> - <term> - <mallctl>prof.thread_active_init</mallctl> - (<type>bool</type>) - <literal>rw</literal> - [<option>--enable-prof</option>] - </term> - <listitem><para>Control the initial setting for <link - linkend="thread.prof.active"><mallctl>thread.prof.active</mallctl></link> - in newly created threads. See the <link - linkend="opt.prof_thread_active_init"><mallctl>opt.prof_thread_active_init</mallctl></link> - option for additional information.</para></listitem> - </varlistentry> - - <varlistentry id="prof.active"> - <term> - <mallctl>prof.active</mallctl> - (<type>bool</type>) - <literal>rw</literal> - [<option>--enable-prof</option>] - </term> - <listitem><para>Control whether sampling is currently active. See the - <link - linkend="opt.prof_active"><mallctl>opt.prof_active</mallctl></link> - option for additional information, as well as the interrelated <link - linkend="thread.prof.active"><mallctl>thread.prof.active</mallctl></link> - mallctl.</para></listitem> - </varlistentry> - - <varlistentry id="prof.dump"> - <term> - <mallctl>prof.dump</mallctl> - (<type>const char *</type>) - <literal>-w</literal> - [<option>--enable-prof</option>] - </term> - <listitem><para>Dump a memory profile to the specified file, or if NULL - is specified, to a file according to the pattern - <filename><prefix>.<pid>.<seq>.m<mseq>.heap</filename>, - where <literal><prefix></literal> is controlled by the - <link - linkend="opt.prof_prefix"><mallctl>opt.prof_prefix</mallctl></link> - option.</para></listitem> - </varlistentry> - - <varlistentry id="prof.gdump"> - <term> - <mallctl>prof.gdump</mallctl> - (<type>bool</type>) - <literal>rw</literal> - [<option>--enable-prof</option>] - </term> - <listitem><para>When enabled, trigger a memory profile dump every time - the total virtual memory exceeds the previous maximum. Profiles are - dumped to files named according to the pattern - <filename><prefix>.<pid>.<seq>.u<useq>.heap</filename>, - where <literal><prefix></literal> is controlled by the <link - linkend="opt.prof_prefix"><mallctl>opt.prof_prefix</mallctl></link> - option.</para></listitem> - </varlistentry> - - <varlistentry id="prof.reset"> - <term> - <mallctl>prof.reset</mallctl> - (<type>size_t</type>) - <literal>-w</literal> - [<option>--enable-prof</option>] - </term> - <listitem><para>Reset all memory profile statistics, and optionally - update the sample rate (see <link - linkend="opt.lg_prof_sample"><mallctl>opt.lg_prof_sample</mallctl></link> - and <link - linkend="prof.lg_sample"><mallctl>prof.lg_sample</mallctl></link>). - </para></listitem> - </varlistentry> - - <varlistentry id="prof.lg_sample"> - <term> - <mallctl>prof.lg_sample</mallctl> - (<type>size_t</type>) - <literal>r-</literal> - [<option>--enable-prof</option>] - </term> - <listitem><para>Get the current sample rate (see <link - linkend="opt.lg_prof_sample"><mallctl>opt.lg_prof_sample</mallctl></link>). - </para></listitem> - </varlistentry> - - <varlistentry id="prof.interval"> - <term> - <mallctl>prof.interval</mallctl> - (<type>uint64_t</type>) - <literal>r-</literal> - [<option>--enable-prof</option>] - </term> - <listitem><para>Average number of bytes allocated between - interval-based profile dumps. See the - <link - linkend="opt.lg_prof_interval"><mallctl>opt.lg_prof_interval</mallctl></link> - option for additional information.</para></listitem> - </varlistentry> - - <varlistentry id="stats.allocated"> - <term> - <mallctl>stats.allocated</mallctl> - (<type>size_t</type>) - <literal>r-</literal> - [<option>--enable-stats</option>] - </term> - <listitem><para>Total number of bytes allocated by the - application.</para></listitem> - </varlistentry> - - <varlistentry id="stats.active"> - <term> - <mallctl>stats.active</mallctl> - (<type>size_t</type>) - <literal>r-</literal> - [<option>--enable-stats</option>] - </term> - <listitem><para>Total number of bytes in active pages allocated by the - application. This is a multiple of the page size, and greater than or - equal to <link - linkend="stats.allocated"><mallctl>stats.allocated</mallctl></link>. - This does not include <link linkend="stats.arenas.i.pdirty"> - <mallctl>stats.arenas.<i>.pdirty</mallctl></link>, - <link linkend="stats.arenas.i.pmuzzy"> - <mallctl>stats.arenas.<i>.pmuzzy</mallctl></link>, nor pages - entirely devoted to allocator metadata.</para></listitem> - </varlistentry> - - <varlistentry id="stats.metadata"> - <term> - <mallctl>stats.metadata</mallctl> - (<type>size_t</type>) - <literal>r-</literal> - [<option>--enable-stats</option>] - </term> - <listitem><para>Total number of bytes dedicated to metadata, which - comprise base allocations used for bootstrap-sensitive allocator - metadata structures (see <link - linkend="stats.arenas.i.base"><mallctl>stats.arenas.<i>.base</mallctl></link>) - and internal allocations (see <link - linkend="stats.arenas.i.internal"><mallctl>stats.arenas.<i>.internal</mallctl></link>). - Transparent huge page (enabled with <link - linkend="opt.metadata_thp">opt.metadata_thp</link>) usage is not - considered.</para></listitem> - </varlistentry> - - <varlistentry id="stats.metadata_thp"> - <term> - <mallctl>stats.metadata_thp</mallctl> - (<type>size_t</type>) - <literal>r-</literal> - [<option>--enable-stats</option>] - </term> - <listitem><para>Number of transparent huge pages (THP) used for - metadata. See <link - linkend="stats.metadata"><mallctl>stats.metadata</mallctl></link> and - <link linkend="opt.metadata_thp">opt.metadata_thp</link>) for - details.</para></listitem> - </varlistentry> - - <varlistentry id="stats.resident"> - <term> - <mallctl>stats.resident</mallctl> - (<type>size_t</type>) - <literal>r-</literal> - [<option>--enable-stats</option>] - </term> - <listitem><para>Maximum number of bytes in physically resident data - pages mapped by the allocator, comprising all pages dedicated to - allocator metadata, pages backing active allocations, and unused dirty - pages. This is a maximum rather than precise because pages may not - actually be physically resident if they correspond to demand-zeroed - virtual memory that has not yet been touched. This is a multiple of the - page size, and is larger than <link - linkend="stats.active"><mallctl>stats.active</mallctl></link>.</para></listitem> - </varlistentry> - - <varlistentry id="stats.mapped"> - <term> - <mallctl>stats.mapped</mallctl> - (<type>size_t</type>) - <literal>r-</literal> - [<option>--enable-stats</option>] - </term> - <listitem><para>Total number of bytes in active extents mapped by the - allocator. This is larger than <link - linkend="stats.active"><mallctl>stats.active</mallctl></link>. This - does not include inactive extents, even those that contain unused dirty - pages, which means that there is no strict ordering between this and - <link - linkend="stats.resident"><mallctl>stats.resident</mallctl></link>.</para></listitem> - </varlistentry> - - <varlistentry id="stats.retained"> - <term> - <mallctl>stats.retained</mallctl> - (<type>size_t</type>) - <literal>r-</literal> - [<option>--enable-stats</option>] - </term> - <listitem><para>Total number of bytes in virtual memory mappings that - were retained rather than being returned to the operating system via - e.g. <citerefentry><refentrytitle>munmap</refentrytitle> - <manvolnum>2</manvolnum></citerefentry> or similar. Retained virtual - memory is typically untouched, decommitted, or purged, so it has no - strongly associated physical memory (see <link - linkend="arena.i.extent_hooks">extent hooks</link> for details). - Retained memory is excluded from mapped memory statistics, e.g. <link - linkend="stats.mapped"><mallctl>stats.mapped</mallctl></link>. - </para></listitem> - </varlistentry> - - <varlistentry id="stats.background_thread.num_threads"> - <term> - <mallctl>stats.background_thread.num_threads</mallctl> - (<type>size_t</type>) - <literal>r-</literal> - [<option>--enable-stats</option>] - </term> - <listitem><para> Number of <link linkend="background_thread">background - threads</link> running currently.</para></listitem> - </varlistentry> - - <varlistentry id="stats.background_thread.num_runs"> - <term> - <mallctl>stats.background_thread.num_runs</mallctl> - (<type>uint64_t</type>) - <literal>r-</literal> - [<option>--enable-stats</option>] - </term> - <listitem><para> Total number of runs from all <link - linkend="background_thread">background threads</link>.</para></listitem> - </varlistentry> - - <varlistentry id="stats.background_thread.run_interval"> - <term> - <mallctl>stats.background_thread.run_interval</mallctl> - (<type>uint64_t</type>) - <literal>r-</literal> - [<option>--enable-stats</option>] - </term> - <listitem><para> Average run interval in nanoseconds of <link - linkend="background_thread">background threads</link>.</para></listitem> - </varlistentry> - - <varlistentry id="stats.mutexes.ctl"> - <term> - <mallctl>stats.mutexes.ctl.{counter};</mallctl> - (<type>counter specific type</type>) - <literal>r-</literal> - [<option>--enable-stats</option>] - </term> - <listitem><para>Statistics on <varname>ctl</varname> mutex (global - scope; mallctl related). <mallctl>{counter}</mallctl> is one of the - counters below:</para> - <varlistentry id="mutex_counters"> - <listitem><para><varname>num_ops</varname> (<type>uint64_t</type>): - Total number of lock acquisition operations on this mutex.</para> - - <para><varname>num_spin_acq</varname> (<type>uint64_t</type>): Number - of times the mutex was spin-acquired. When the mutex is currently - locked and cannot be acquired immediately, a short period of - spin-retry within jemalloc will be performed. Acquired through spin - generally means the contention was lightweight and not causing context - switches.</para> - - <para><varname>num_wait</varname> (<type>uint64_t</type>): Number of - times the mutex was wait-acquired, which means the mutex contention - was not solved by spin-retry, and blocking operation was likely - involved in order to acquire the mutex. This event generally implies - higher cost / longer delay, and should be investigated if it happens - often.</para> - - <para><varname>max_wait_time</varname> (<type>uint64_t</type>): - Maximum length of time in nanoseconds spent on a single wait-acquired - lock operation. Note that to avoid profiling overhead on the common - path, this does not consider spin-acquired cases.</para> - - <para><varname>total_wait_time</varname> (<type>uint64_t</type>): - Cumulative time in nanoseconds spent on wait-acquired lock operations. - Similarly, spin-acquired cases are not considered.</para> - - <para><varname>max_num_thds</varname> (<type>uint32_t</type>): Maximum - number of threads waiting on this mutex simultaneously. Similarly, - spin-acquired cases are not considered.</para> - - <para><varname>num_owner_switch</varname> (<type>uint64_t</type>): - Number of times the current mutex owner is different from the previous - one. This event does not generally imply an issue; rather it is an - indicator of how often the protected data are accessed by different - threads. - </para> - </listitem> - </varlistentry> - </listitem> - </varlistentry> - - <varlistentry id="stats.mutexes.background_thread"> - <term> - <mallctl>stats.mutexes.background_thread.{counter}</mallctl> - (<type>counter specific type</type>) <literal>r-</literal> - [<option>--enable-stats</option>] - </term> - <listitem><para>Statistics on <varname>background_thread</varname> mutex - (global scope; <link - linkend="background_thread"><mallctl>background_thread</mallctl></link> - related). <mallctl>{counter}</mallctl> is one of the counters in <link - linkend="mutex_counters">mutex profiling - counters</link>.</para></listitem> - </varlistentry> - - <varlistentry id="stats.mutexes.prof"> - <term> - <mallctl>stats.mutexes.prof.{counter}</mallctl> - (<type>counter specific type</type>) <literal>r-</literal> - [<option>--enable-stats</option>] - </term> - <listitem><para>Statistics on <varname>prof</varname> mutex (global - scope; profiling related). <mallctl>{counter}</mallctl> is one of the - counters in <link linkend="mutex_counters">mutex profiling - counters</link>.</para></listitem> - </varlistentry> - - <varlistentry id="stats.mutexes.reset"> - <term> - <mallctl>stats.mutexes.reset</mallctl> - (<type>void</type>) <literal>--</literal> - [<option>--enable-stats</option>] - </term> - <listitem><para>Reset all mutex profile statistics, including global - mutexes, arena mutexes and bin mutexes.</para></listitem> - </varlistentry> - - <varlistentry id="stats.arenas.i.dss"> - <term> - <mallctl>stats.arenas.<i>.dss</mallctl> - (<type>const char *</type>) - <literal>r-</literal> - </term> - <listitem><para>dss (<citerefentry><refentrytitle>sbrk</refentrytitle> - <manvolnum>2</manvolnum></citerefentry>) allocation precedence as - related to <citerefentry><refentrytitle>mmap</refentrytitle> - <manvolnum>2</manvolnum></citerefentry> allocation. See <link - linkend="opt.dss"><mallctl>opt.dss</mallctl></link> for details. - </para></listitem> - </varlistentry> - - <varlistentry id="stats.arenas.i.dirty_decay_ms"> - <term> - <mallctl>stats.arenas.<i>.dirty_decay_ms</mallctl> - (<type>ssize_t</type>) - <literal>r-</literal> - </term> - <listitem><para>Approximate time in milliseconds from the creation of a - set of unused dirty pages until an equivalent set of unused dirty pages - is purged and/or reused. See <link - linkend="opt.dirty_decay_ms"><mallctl>opt.dirty_decay_ms</mallctl></link> - for details.</para></listitem> - </varlistentry> - - <varlistentry id="stats.arenas.i.muzzy_decay_ms"> - <term> - <mallctl>stats.arenas.<i>.muzzy_decay_ms</mallctl> - (<type>ssize_t</type>) - <literal>r-</literal> - </term> - <listitem><para>Approximate time in milliseconds from the creation of a - set of unused muzzy pages until an equivalent set of unused muzzy pages - is purged and/or reused. See <link - linkend="opt.muzzy_decay_ms"><mallctl>opt.muzzy_decay_ms</mallctl></link> - for details.</para></listitem> - </varlistentry> - - <varlistentry id="stats.arenas.i.nthreads"> - <term> - <mallctl>stats.arenas.<i>.nthreads</mallctl> - (<type>unsigned</type>) - <literal>r-</literal> - </term> - <listitem><para>Number of threads currently assigned to - arena.</para></listitem> - </varlistentry> - - <varlistentry id="stats.arenas.i.uptime"> - <term> - <mallctl>stats.arenas.<i>.uptime</mallctl> - (<type>uint64_t</type>) - <literal>r-</literal> - </term> - <listitem><para>Time elapsed (in nanoseconds) since the arena was - created. If <i> equals <constant>0</constant> or - <constant>MALLCTL_ARENAS_ALL</constant>, this is the uptime since malloc - initialization.</para></listitem> - </varlistentry> - - <varlistentry id="stats.arenas.i.pactive"> - <term> - <mallctl>stats.arenas.<i>.pactive</mallctl> - (<type>size_t</type>) - <literal>r-</literal> - </term> - <listitem><para>Number of pages in active extents.</para></listitem> - </varlistentry> - - <varlistentry id="stats.arenas.i.pdirty"> - <term> - <mallctl>stats.arenas.<i>.pdirty</mallctl> - (<type>size_t</type>) - <literal>r-</literal> - </term> - <listitem><para>Number of pages within unused extents that are - potentially dirty, and for which <function>madvise()</function> or - similar has not been called. See <link - linkend="opt.dirty_decay_ms"><mallctl>opt.dirty_decay_ms</mallctl></link> - for a description of dirty pages.</para></listitem> - </varlistentry> - - <varlistentry id="stats.arenas.i.pmuzzy"> - <term> - <mallctl>stats.arenas.<i>.pmuzzy</mallctl> - (<type>size_t</type>) - <literal>r-</literal> - </term> - <listitem><para>Number of pages within unused extents that are muzzy. - See <link - linkend="opt.muzzy_decay_ms"><mallctl>opt.muzzy_decay_ms</mallctl></link> - for a description of muzzy pages.</para></listitem> - </varlistentry> - - <varlistentry id="stats.arenas.i.mapped"> - <term> - <mallctl>stats.arenas.<i>.mapped</mallctl> - (<type>size_t</type>) - <literal>r-</literal> - [<option>--enable-stats</option>] - </term> - <listitem><para>Number of mapped bytes.</para></listitem> - </varlistentry> - - <varlistentry id="stats.arenas.i.retained"> - <term> - <mallctl>stats.arenas.<i>.retained</mallctl> - (<type>size_t</type>) - <literal>r-</literal> - [<option>--enable-stats</option>] - </term> - <listitem><para>Number of retained bytes. See <link - linkend="stats.retained"><mallctl>stats.retained</mallctl></link> for - details.</para></listitem> - </varlistentry> - - <varlistentry id="stats.arenas.i.extent_avail"> - <term> - <mallctl>stats.arenas.<i>.extent_avail</mallctl> - (<type>size_t</type>) - <literal>r-</literal> - [<option>--enable-stats</option>] - </term> - <listitem><para>Number of allocated (but unused) extent structs in this - arena.</para></listitem> - </varlistentry> - - <varlistentry id="stats.arenas.i.base"> - <term> - <mallctl>stats.arenas.<i>.base</mallctl> - (<type>size_t</type>) - <literal>r-</literal> - [<option>--enable-stats</option>] - </term> - <listitem><para> - Number of bytes dedicated to bootstrap-sensitive allocator metadata - structures.</para></listitem> - </varlistentry> - - <varlistentry id="stats.arenas.i.internal"> - <term> - <mallctl>stats.arenas.<i>.internal</mallctl> - (<type>size_t</type>) - <literal>r-</literal> - [<option>--enable-stats</option>] - </term> - <listitem><para>Number of bytes dedicated to internal allocations. - Internal allocations differ from application-originated allocations in - that they are for internal use, and that they are omitted from heap - profiles.</para></listitem> - </varlistentry> - - <varlistentry id="stats.arenas.i.metadata_thp"> - <term> - <mallctl>stats.arenas.<i>.metadata_thp</mallctl> - (<type>size_t</type>) - <literal>r-</literal> - [<option>--enable-stats</option>] - </term> - <listitem><para>Number of transparent huge pages (THP) used for - metadata. See <link linkend="opt.metadata_thp">opt.metadata_thp</link> - for details.</para></listitem> - </varlistentry> - - <varlistentry id="stats.arenas.i.resident"> - <term> - <mallctl>stats.arenas.<i>.resident</mallctl> - (<type>size_t</type>) - <literal>r-</literal> - [<option>--enable-stats</option>] - </term> - <listitem><para>Maximum number of bytes in physically resident data - pages mapped by the arena, comprising all pages dedicated to allocator - metadata, pages backing active allocations, and unused dirty pages. - This is a maximum rather than precise because pages may not actually be - physically resident if they correspond to demand-zeroed virtual memory - that has not yet been touched. This is a multiple of the page - size.</para></listitem> - </varlistentry> - - <varlistentry id="stats.arenas.i.dirty_npurge"> - <term> - <mallctl>stats.arenas.<i>.dirty_npurge</mallctl> - (<type>uint64_t</type>) - <literal>r-</literal> - [<option>--enable-stats</option>] - </term> - <listitem><para>Number of dirty page purge sweeps performed. - </para></listitem> - </varlistentry> - - <varlistentry id="stats.arenas.i.dirty_nmadvise"> - <term> - <mallctl>stats.arenas.<i>.dirty_nmadvise</mallctl> - (<type>uint64_t</type>) - <literal>r-</literal> - [<option>--enable-stats</option>] - </term> - <listitem><para>Number of <function>madvise()</function> or similar - calls made to purge dirty pages.</para></listitem> - </varlistentry> - - <varlistentry id="stats.arenas.i.dirty_purged"> - <term> - <mallctl>stats.arenas.<i>.dirty_purged</mallctl> - (<type>uint64_t</type>) - <literal>r-</literal> - [<option>--enable-stats</option>] - </term> - <listitem><para>Number of dirty pages purged.</para></listitem> - </varlistentry> - - <varlistentry id="stats.arenas.i.muzzy_npurge"> - <term> - <mallctl>stats.arenas.<i>.muzzy_npurge</mallctl> - (<type>uint64_t</type>) - <literal>r-</literal> - [<option>--enable-stats</option>] - </term> - <listitem><para>Number of muzzy page purge sweeps performed. - </para></listitem> - </varlistentry> - - <varlistentry id="stats.arenas.i.muzzy_nmadvise"> - <term> - <mallctl>stats.arenas.<i>.muzzy_nmadvise</mallctl> - (<type>uint64_t</type>) - <literal>r-</literal> - [<option>--enable-stats</option>] - </term> - <listitem><para>Number of <function>madvise()</function> or similar - calls made to purge muzzy pages.</para></listitem> - </varlistentry> - - <varlistentry id="stats.arenas.i.muzzy_purged"> - <term> - <mallctl>stats.arenas.<i>.muzzy_purged</mallctl> - (<type>uint64_t</type>) - <literal>r-</literal> - [<option>--enable-stats</option>] - </term> - <listitem><para>Number of muzzy pages purged.</para></listitem> - </varlistentry> - - <varlistentry id="stats.arenas.i.small.allocated"> - <term> - <mallctl>stats.arenas.<i>.small.allocated</mallctl> - (<type>size_t</type>) - <literal>r-</literal> - [<option>--enable-stats</option>] - </term> - <listitem><para>Number of bytes currently allocated by small objects. - </para></listitem> - </varlistentry> - - <varlistentry id="stats.arenas.i.small.nmalloc"> - <term> - <mallctl>stats.arenas.<i>.small.nmalloc</mallctl> - (<type>uint64_t</type>) - <literal>r-</literal> - [<option>--enable-stats</option>] - </term> - <listitem><para>Cumulative number of times a small allocation was - requested from the arena's bins, whether to fill the relevant tcache if - <link linkend="opt.tcache"><mallctl>opt.tcache</mallctl></link> is - enabled, or to directly satisfy an allocation request - otherwise.</para></listitem> - </varlistentry> - - <varlistentry id="stats.arenas.i.small.ndalloc"> - <term> - <mallctl>stats.arenas.<i>.small.ndalloc</mallctl> - (<type>uint64_t</type>) - <literal>r-</literal> - [<option>--enable-stats</option>] - </term> - <listitem><para>Cumulative number of times a small allocation was - returned to the arena's bins, whether to flush the relevant tcache if - <link linkend="opt.tcache"><mallctl>opt.tcache</mallctl></link> is - enabled, or to directly deallocate an allocation - otherwise.</para></listitem> - </varlistentry> - - <varlistentry id="stats.arenas.i.small.nrequests"> - <term> - <mallctl>stats.arenas.<i>.small.nrequests</mallctl> - (<type>uint64_t</type>) - <literal>r-</literal> - [<option>--enable-stats</option>] - </term> - <listitem><para>Cumulative number of allocation requests satisfied by - all bin size classes.</para></listitem> - </varlistentry> - - <varlistentry id="stats.arenas.i.small.nfills"> - <term> - <mallctl>stats.arenas.<i>.small.nfills</mallctl> - (<type>uint64_t</type>) - <literal>r-</literal> - [<option>--enable-stats</option>] - </term> - <listitem><para>Cumulative number of tcache fills by all small size - classes.</para></listitem> - </varlistentry> - - <varlistentry id="stats.arenas.i.small.nflushes"> - <term> - <mallctl>stats.arenas.<i>.small.nflushes</mallctl> - (<type>uint64_t</type>) - <literal>r-</literal> - [<option>--enable-stats</option>] - </term> - <listitem><para>Cumulative number of tcache flushes by all small size - classes.</para></listitem> - </varlistentry> - - <varlistentry id="stats.arenas.i.large.allocated"> - <term> - <mallctl>stats.arenas.<i>.large.allocated</mallctl> - (<type>size_t</type>) - <literal>r-</literal> - [<option>--enable-stats</option>] - </term> - <listitem><para>Number of bytes currently allocated by large objects. - </para></listitem> - </varlistentry> - - <varlistentry id="stats.arenas.i.large.nmalloc"> - <term> - <mallctl>stats.arenas.<i>.large.nmalloc</mallctl> - (<type>uint64_t</type>) - <literal>r-</literal> - [<option>--enable-stats</option>] - </term> - <listitem><para>Cumulative number of times a large extent was allocated - from the arena, whether to fill the relevant tcache if <link - linkend="opt.tcache"><mallctl>opt.tcache</mallctl></link> is enabled and - the size class is within the range being cached, or to directly satisfy - an allocation request otherwise.</para></listitem> - </varlistentry> - - <varlistentry id="stats.arenas.i.large.ndalloc"> - <term> - <mallctl>stats.arenas.<i>.large.ndalloc</mallctl> - (<type>uint64_t</type>) - <literal>r-</literal> - [<option>--enable-stats</option>] - </term> - <listitem><para>Cumulative number of times a large extent was returned - to the arena, whether to flush the relevant tcache if <link - linkend="opt.tcache"><mallctl>opt.tcache</mallctl></link> is enabled and - the size class is within the range being cached, or to directly - deallocate an allocation otherwise.</para></listitem> - </varlistentry> - - <varlistentry id="stats.arenas.i.large.nrequests"> - <term> - <mallctl>stats.arenas.<i>.large.nrequests</mallctl> - (<type>uint64_t</type>) - <literal>r-</literal> - [<option>--enable-stats</option>] - </term> - <listitem><para>Cumulative number of allocation requests satisfied by - all large size classes.</para></listitem> - </varlistentry> - - <varlistentry id="stats.arenas.i.large.nfills"> - <term> - <mallctl>stats.arenas.<i>.large.nfills</mallctl> - (<type>uint64_t</type>) - <literal>r-</literal> - [<option>--enable-stats</option>] - </term> - <listitem><para>Cumulative number of tcache fills by all large size - classes.</para></listitem> - </varlistentry> - - <varlistentry id="stats.arenas.i.large.nflushes"> - <term> - <mallctl>stats.arenas.<i>.large.nflushes</mallctl> - (<type>uint64_t</type>) - <literal>r-</literal> - [<option>--enable-stats</option>] - </term> - <listitem><para>Cumulative number of tcache flushes by all large size - classes.</para></listitem> - </varlistentry> - - <varlistentry id="stats.arenas.i.bins.j.nmalloc"> - <term> - <mallctl>stats.arenas.<i>.bins.<j>.nmalloc</mallctl> - (<type>uint64_t</type>) - <literal>r-</literal> - [<option>--enable-stats</option>] - </term> - <listitem><para>Cumulative number of times a bin region of the - corresponding size class was allocated from the arena, whether to fill - the relevant tcache if <link - linkend="opt.tcache"><mallctl>opt.tcache</mallctl></link> is enabled, or - to directly satisfy an allocation request otherwise.</para></listitem> - </varlistentry> - - <varlistentry id="stats.arenas.i.bins.j.ndalloc"> - <term> - <mallctl>stats.arenas.<i>.bins.<j>.ndalloc</mallctl> - (<type>uint64_t</type>) - <literal>r-</literal> - [<option>--enable-stats</option>] - </term> - <listitem><para>Cumulative number of times a bin region of the - corresponding size class was returned to the arena, whether to flush the - relevant tcache if <link - linkend="opt.tcache"><mallctl>opt.tcache</mallctl></link> is enabled, or - to directly deallocate an allocation otherwise.</para></listitem> - </varlistentry> - - <varlistentry id="stats.arenas.i.bins.j.nrequests"> - <term> - <mallctl>stats.arenas.<i>.bins.<j>.nrequests</mallctl> - (<type>uint64_t</type>) - <literal>r-</literal> - [<option>--enable-stats</option>] - </term> - <listitem><para>Cumulative number of allocation requests satisfied by - bin regions of the corresponding size class.</para></listitem> - </varlistentry> - - <varlistentry id="stats.arenas.i.bins.j.curregs"> - <term> - <mallctl>stats.arenas.<i>.bins.<j>.curregs</mallctl> - (<type>size_t</type>) - <literal>r-</literal> - [<option>--enable-stats</option>] - </term> - <listitem><para>Current number of regions for this size - class.</para></listitem> - </varlistentry> - - <varlistentry id="stats.arenas.i.bins.j.nfills"> - <term> - <mallctl>stats.arenas.<i>.bins.<j>.nfills</mallctl> - (<type>uint64_t</type>) - <literal>r-</literal> - </term> - <listitem><para>Cumulative number of tcache fills.</para></listitem> - </varlistentry> - - <varlistentry id="stats.arenas.i.bins.j.nflushes"> - <term> - <mallctl>stats.arenas.<i>.bins.<j>.nflushes</mallctl> - (<type>uint64_t</type>) - <literal>r-</literal> - </term> - <listitem><para>Cumulative number of tcache flushes.</para></listitem> - </varlistentry> - - <varlistentry id="stats.arenas.i.bins.j.nslabs"> - <term> - <mallctl>stats.arenas.<i>.bins.<j>.nslabs</mallctl> - (<type>uint64_t</type>) - <literal>r-</literal> - [<option>--enable-stats</option>] - </term> - <listitem><para>Cumulative number of slabs created.</para></listitem> - </varlistentry> - - <varlistentry id="stats.arenas.i.bins.j.nreslabs"> - <term> - <mallctl>stats.arenas.<i>.bins.<j>.nreslabs</mallctl> - (<type>uint64_t</type>) - <literal>r-</literal> - [<option>--enable-stats</option>] - </term> - <listitem><para>Cumulative number of times the current slab from which - to allocate changed.</para></listitem> - </varlistentry> - - <varlistentry id="stats.arenas.i.bins.j.curslabs"> - <term> - <mallctl>stats.arenas.<i>.bins.<j>.curslabs</mallctl> - (<type>size_t</type>) - <literal>r-</literal> - [<option>--enable-stats</option>] - </term> - <listitem><para>Current number of slabs.</para></listitem> - </varlistentry> - - - <varlistentry id="stats.arenas.i.bins.j.nonfull_slabs"> - <term> - <mallctl>stats.arenas.<i>.bins.<j>.nonfull_slabs</mallctl> - (<type>size_t</type>) - <literal>r-</literal> - [<option>--enable-stats</option>] - </term> - <listitem><para>Current number of nonfull slabs.</para></listitem> - </varlistentry> - - <varlistentry id="stats.arenas.i.bins.mutex"> - <term> - <mallctl>stats.arenas.<i>.bins.<j>.mutex.{counter}</mallctl> - (<type>counter specific type</type>) <literal>r-</literal> - [<option>--enable-stats</option>] - </term> - <listitem><para>Statistics on - <varname>arena.<i>.bins.<j></varname> mutex (arena bin - scope; bin operation related). <mallctl>{counter}</mallctl> is one of - the counters in <link linkend="mutex_counters">mutex profiling - counters</link>.</para></listitem> - </varlistentry> - - <varlistentry id="stats.arenas.i.extents.n"> - <term> - <mallctl>stats.arenas.<i>.extents.<j>.n{extent_type}</mallctl> - (<type>size_t</type>) - <literal>r-</literal> - [<option>--enable-stats</option>] - </term> - <listitem><para> Number of extents of the given type in this arena in - the bucket corresponding to page size index <j>. The extent type - is one of dirty, muzzy, or retained.</para></listitem> - </varlistentry> - - <varlistentry id="stats.arenas.i.extents.bytes"> - <term> - <mallctl>stats.arenas.<i>.extents.<j>.{extent_type}_bytes</mallctl> - (<type>size_t</type>) - <literal>r-</literal> - [<option>--enable-stats</option>] - </term> - <listitem><para> Sum of the bytes managed by extents of the given type - in this arena in the bucket corresponding to page size index <j>. - The extent type is one of dirty, muzzy, or retained.</para></listitem> - </varlistentry> - - <varlistentry id="stats.arenas.i.lextents.j.nmalloc"> - <term> - <mallctl>stats.arenas.<i>.lextents.<j>.nmalloc</mallctl> - (<type>uint64_t</type>) - <literal>r-</literal> - [<option>--enable-stats</option>] - </term> - <listitem><para>Cumulative number of times a large extent of the - corresponding size class was allocated from the arena, whether to fill - the relevant tcache if <link - linkend="opt.tcache"><mallctl>opt.tcache</mallctl></link> is enabled and - the size class is within the range being cached, or to directly satisfy - an allocation request otherwise.</para></listitem> - </varlistentry> - - <varlistentry id="stats.arenas.i.lextents.j.ndalloc"> - <term> - <mallctl>stats.arenas.<i>.lextents.<j>.ndalloc</mallctl> - (<type>uint64_t</type>) - <literal>r-</literal> - [<option>--enable-stats</option>] - </term> - <listitem><para>Cumulative number of times a large extent of the - corresponding size class was returned to the arena, whether to flush the - relevant tcache if <link - linkend="opt.tcache"><mallctl>opt.tcache</mallctl></link> is enabled and - the size class is within the range being cached, or to directly - deallocate an allocation otherwise.</para></listitem> - </varlistentry> - - <varlistentry id="stats.arenas.i.lextents.j.nrequests"> - <term> - <mallctl>stats.arenas.<i>.lextents.<j>.nrequests</mallctl> - (<type>uint64_t</type>) - <literal>r-</literal> - [<option>--enable-stats</option>] - </term> - <listitem><para>Cumulative number of allocation requests satisfied by - large extents of the corresponding size class.</para></listitem> - </varlistentry> - - <varlistentry id="stats.arenas.i.lextents.j.curlextents"> - <term> - <mallctl>stats.arenas.<i>.lextents.<j>.curlextents</mallctl> - (<type>size_t</type>) - <literal>r-</literal> - [<option>--enable-stats</option>] - </term> - <listitem><para>Current number of large allocations for this size class. - </para></listitem> - </varlistentry> - - <varlistentry id="stats.arenas.i.mutexes.large"> - <term> - <mallctl>stats.arenas.<i>.mutexes.large.{counter}</mallctl> - (<type>counter specific type</type>) <literal>r-</literal> - [<option>--enable-stats</option>] - </term> - <listitem><para>Statistics on <varname>arena.<i>.large</varname> - mutex (arena scope; large allocation related). - <mallctl>{counter}</mallctl> is one of the counters in <link - linkend="mutex_counters">mutex profiling - counters</link>.</para></listitem> - </varlistentry> - - <varlistentry id="stats.arenas.i.mutexes.extent_avail"> - <term> - <mallctl>stats.arenas.<i>.mutexes.extent_avail.{counter}</mallctl> - (<type>counter specific type</type>) <literal>r-</literal> - [<option>--enable-stats</option>] - </term> - <listitem><para>Statistics on <varname>arena.<i>.extent_avail - </varname> mutex (arena scope; extent avail related). - <mallctl>{counter}</mallctl> is one of the counters in <link - linkend="mutex_counters">mutex profiling - counters</link>.</para></listitem> - </varlistentry> - - <varlistentry id="stats.arenas.i.mutexes.extents_dirty"> - <term> - <mallctl>stats.arenas.<i>.mutexes.extents_dirty.{counter}</mallctl> - (<type>counter specific type</type>) <literal>r-</literal> - [<option>--enable-stats</option>] - </term> - <listitem><para>Statistics on <varname>arena.<i>.extents_dirty - </varname> mutex (arena scope; dirty extents related). - <mallctl>{counter}</mallctl> is one of the counters in <link - linkend="mutex_counters">mutex profiling - counters</link>.</para></listitem> - </varlistentry> - - <varlistentry id="stats.arenas.i.mutexes.extents_muzzy"> - <term> - <mallctl>stats.arenas.<i>.mutexes.extents_muzzy.{counter}</mallctl> - (<type>counter specific type</type>) <literal>r-</literal> - [<option>--enable-stats</option>] - </term> - <listitem><para>Statistics on <varname>arena.<i>.extents_muzzy - </varname> mutex (arena scope; muzzy extents related). - <mallctl>{counter}</mallctl> is one of the counters in <link - linkend="mutex_counters">mutex profiling - counters</link>.</para></listitem> - </varlistentry> - - <varlistentry id="stats.arenas.i.mutexes.extents_retained"> - <term> - <mallctl>stats.arenas.<i>.mutexes.extents_retained.{counter}</mallctl> - (<type>counter specific type</type>) <literal>r-</literal> - [<option>--enable-stats</option>] - </term> - <listitem><para>Statistics on <varname>arena.<i>.extents_retained - </varname> mutex (arena scope; retained extents related). - <mallctl>{counter}</mallctl> is one of the counters in <link - linkend="mutex_counters">mutex profiling - counters</link>.</para></listitem> - </varlistentry> - - <varlistentry id="stats.arenas.i.mutexes.decay_dirty"> - <term> - <mallctl>stats.arenas.<i>.mutexes.decay_dirty.{counter}</mallctl> - (<type>counter specific type</type>) <literal>r-</literal> - [<option>--enable-stats</option>] - </term> - <listitem><para>Statistics on <varname>arena.<i>.decay_dirty - </varname> mutex (arena scope; decay for dirty pages related). - <mallctl>{counter}</mallctl> is one of the counters in <link - linkend="mutex_counters">mutex profiling - counters</link>.</para></listitem> - </varlistentry> - - <varlistentry id="stats.arenas.i.mutexes.decay_muzzy"> - <term> - <mallctl>stats.arenas.<i>.mutexes.decay_muzzy.{counter}</mallctl> - (<type>counter specific type</type>) <literal>r-</literal> - [<option>--enable-stats</option>] - </term> - <listitem><para>Statistics on <varname>arena.<i>.decay_muzzy - </varname> mutex (arena scope; decay for muzzy pages related). - <mallctl>{counter}</mallctl> is one of the counters in <link - linkend="mutex_counters">mutex profiling - counters</link>.</para></listitem> - </varlistentry> - - <varlistentry id="stats.arenas.i.mutexes.base"> - <term> - <mallctl>stats.arenas.<i>.mutexes.base.{counter}</mallctl> - (<type>counter specific type</type>) <literal>r-</literal> - [<option>--enable-stats</option>] - </term> - <listitem><para>Statistics on <varname>arena.<i>.base</varname> - mutex (arena scope; base allocator related). - <mallctl>{counter}</mallctl> is one of the counters in <link - linkend="mutex_counters">mutex profiling - counters</link>.</para></listitem> - </varlistentry> - - <varlistentry id="stats.arenas.i.mutexes.tcache_list"> - <term> - <mallctl>stats.arenas.<i>.mutexes.tcache_list.{counter}</mallctl> - (<type>counter specific type</type>) <literal>r-</literal> - [<option>--enable-stats</option>] - </term> - <listitem><para>Statistics on - <varname>arena.<i>.tcache_list</varname> mutex (arena scope; - tcache to arena association related). This mutex is expected to be - accessed less often. <mallctl>{counter}</mallctl> is one of the - counters in <link linkend="mutex_counters">mutex profiling - counters</link>.</para></listitem> - </varlistentry> - - </variablelist> - </refsect1> - <refsect1 id="heap_profile_format"> - <title>HEAP PROFILE FORMAT</title> - <para>Although the heap profiling functionality was originally designed to - be compatible with the - <command>pprof</command> command that is developed as part of the <ulink - url="http://code.google.com/p/gperftools/">gperftools - package</ulink>, the addition of per thread heap profiling functionality - required a different heap profile format. The <command>jeprof</command> - command is derived from <command>pprof</command>, with enhancements to - support the heap profile format described here.</para> - - <para>In the following hypothetical heap profile, <constant>[...]</constant> - indicates elision for the sake of compactness. <programlisting><![CDATA[ -heap_v2/524288 - t*: 28106: 56637512 [0: 0] - [...] - t3: 352: 16777344 [0: 0] - [...] - t99: 17754: 29341640 [0: 0] - [...] -@ 0x5f86da8 0x5f5a1dc [...] 0x29e4d4e 0xa200316 0xabb2988 [...] - t*: 13: 6688 [0: 0] - t3: 12: 6496 [0: ] - t99: 1: 192 [0: 0] -[...] - -MAPPED_LIBRARIES: -[...]]]></programlisting> The following matches the above heap profile, but most -tokens are replaced with <constant><description></constant> to indicate -descriptions of the corresponding fields. <programlisting><![CDATA[ -<heap_profile_format_version>/<mean_sample_interval> - <aggregate>: <curobjs>: <curbytes> [<cumobjs>: <cumbytes>] - [...] - <thread_3_aggregate>: <curobjs>: <curbytes>[<cumobjs>: <cumbytes>] - [...] - <thread_99_aggregate>: <curobjs>: <curbytes>[<cumobjs>: <cumbytes>] - [...] -@ <top_frame> <frame> [...] <frame> <frame> <frame> [...] - <backtrace_aggregate>: <curobjs>: <curbytes> [<cumobjs>: <cumbytes>] - <backtrace_thread_3>: <curobjs>: <curbytes> [<cumobjs>: <cumbytes>] - <backtrace_thread_99>: <curobjs>: <curbytes> [<cumobjs>: <cumbytes>] -[...] - -MAPPED_LIBRARIES: -</proc/<pid>/maps>]]></programlisting></para> - </refsect1> - - <refsect1 id="debugging_malloc_problems"> - <title>DEBUGGING MALLOC PROBLEMS</title> - <para>When debugging, it is a good idea to configure/build jemalloc with - the <option>--enable-debug</option> and <option>--enable-fill</option> - options, and recompile the program with suitable options and symbols for - debugger support. When so configured, jemalloc incorporates a wide variety - of run-time assertions that catch application errors such as double-free, - write-after-free, etc.</para> - - <para>Programs often accidentally depend on <quote>uninitialized</quote> - memory actually being filled with zero bytes. Junk filling - (see the <link linkend="opt.junk"><mallctl>opt.junk</mallctl></link> - option) tends to expose such bugs in the form of obviously incorrect - results and/or coredumps. Conversely, zero - filling (see the <link - linkend="opt.zero"><mallctl>opt.zero</mallctl></link> option) eliminates - the symptoms of such bugs. Between these two options, it is usually - possible to quickly detect, diagnose, and eliminate such bugs.</para> - - <para>This implementation does not provide much detail about the problems - it detects, because the performance impact for storing such information - would be prohibitive.</para> - </refsect1> - <refsect1 id="diagnostic_messages"> - <title>DIAGNOSTIC MESSAGES</title> - <para>If any of the memory allocation/deallocation functions detect an - error or warning condition, a message will be printed to file descriptor - <constant>STDERR_FILENO</constant>. Errors will result in the process - dumping core. If the <link - linkend="opt.abort"><mallctl>opt.abort</mallctl></link> option is set, most - warnings are treated as errors.</para> - - <para>The <varname>malloc_message</varname> variable allows the programmer - to override the function which emits the text strings forming the errors - and warnings if for some reason the <constant>STDERR_FILENO</constant> file - descriptor is not suitable for this. - <function>malloc_message()</function> takes the - <parameter>cbopaque</parameter> pointer argument that is - <constant>NULL</constant> unless overridden by the arguments in a call to - <function>malloc_stats_print()</function>, followed by a string - pointer. Please note that doing anything which tries to allocate memory in - this function is likely to result in a crash or deadlock.</para> - - <para>All messages are prefixed by - <quote><computeroutput><jemalloc>: </computeroutput></quote>.</para> - </refsect1> - <refsect1 id="return_values"> - <title>RETURN VALUES</title> - <refsect2> - <title>Standard API</title> - <para>The <function>malloc()</function> and - <function>calloc()</function> functions return a pointer to the - allocated memory if successful; otherwise a <constant>NULL</constant> - pointer is returned and <varname>errno</varname> is set to - <errorname>ENOMEM</errorname>.</para> - - <para>The <function>posix_memalign()</function> function - returns the value 0 if successful; otherwise it returns an error value. - The <function>posix_memalign()</function> function will fail - if: - <variablelist> - <varlistentry> - <term><errorname>EINVAL</errorname></term> - - <listitem><para>The <parameter>alignment</parameter> parameter is - not a power of 2 at least as large as - <code language="C">sizeof(<type>void *</type>)</code>. - </para></listitem> - </varlistentry> - <varlistentry> - <term><errorname>ENOMEM</errorname></term> - - <listitem><para>Memory allocation error.</para></listitem> - </varlistentry> - </variablelist> - </para> - - <para>The <function>aligned_alloc()</function> function returns - a pointer to the allocated memory if successful; otherwise a - <constant>NULL</constant> pointer is returned and - <varname>errno</varname> is set. The - <function>aligned_alloc()</function> function will fail if: - <variablelist> - <varlistentry> - <term><errorname>EINVAL</errorname></term> - - <listitem><para>The <parameter>alignment</parameter> parameter is - not a power of 2. - </para></listitem> - </varlistentry> - <varlistentry> - <term><errorname>ENOMEM</errorname></term> - - <listitem><para>Memory allocation error.</para></listitem> - </varlistentry> - </variablelist> - </para> - - <para>The <function>realloc()</function> function returns a - pointer, possibly identical to <parameter>ptr</parameter>, to the - allocated memory if successful; otherwise a <constant>NULL</constant> - pointer is returned, and <varname>errno</varname> is set to - <errorname>ENOMEM</errorname> if the error was the result of an - allocation failure. The <function>realloc()</function> - function always leaves the original buffer intact when an error occurs. - </para> - - <para>The <function>free()</function> function returns no - value.</para> - </refsect2> - <refsect2> - <title>Non-standard API</title> - <para>The <function>mallocx()</function> and - <function>rallocx()</function> functions return a pointer to - the allocated memory if successful; otherwise a <constant>NULL</constant> - pointer is returned to indicate insufficient contiguous memory was - available to service the allocation request. </para> - - <para>The <function>xallocx()</function> function returns the - real size of the resulting resized allocation pointed to by - <parameter>ptr</parameter>, which is a value less than - <parameter>size</parameter> if the allocation could not be adequately - grown in place. </para> - - <para>The <function>sallocx()</function> function returns the - real size of the allocation pointed to by <parameter>ptr</parameter>. - </para> - - <para>The <function>nallocx()</function> returns the real size - that would result from a successful equivalent - <function>mallocx()</function> function call, or zero if - insufficient memory is available to perform the size computation. </para> - - <para>The <function>mallctl()</function>, - <function>mallctlnametomib()</function>, and - <function>mallctlbymib()</function> functions return 0 on - success; otherwise they return an error value. The functions will fail - if: - <variablelist> - <varlistentry> - <term><errorname>EINVAL</errorname></term> - - <listitem><para><parameter>newp</parameter> is not - <constant>NULL</constant>, and <parameter>newlen</parameter> is too - large or too small. Alternatively, <parameter>*oldlenp</parameter> - is too large or too small; in this case as much data as possible - are read despite the error.</para></listitem> - </varlistentry> - <varlistentry> - <term><errorname>ENOENT</errorname></term> - - <listitem><para><parameter>name</parameter> or - <parameter>mib</parameter> specifies an unknown/invalid - value.</para></listitem> - </varlistentry> - <varlistentry> - <term><errorname>EPERM</errorname></term> - - <listitem><para>Attempt to read or write void value, or attempt to - write read-only value.</para></listitem> - </varlistentry> - <varlistentry> - <term><errorname>EAGAIN</errorname></term> - - <listitem><para>A memory allocation failure - occurred.</para></listitem> - </varlistentry> - <varlistentry> - <term><errorname>EFAULT</errorname></term> - - <listitem><para>An interface with side effects failed in some way - not directly related to <function>mallctl*()</function> - read/write processing.</para></listitem> - </varlistentry> - </variablelist> - </para> - - <para>The <function>malloc_usable_size()</function> function - returns the usable size of the allocation pointed to by - <parameter>ptr</parameter>. </para> - </refsect2> - </refsect1> - <refsect1 id="environment"> - <title>ENVIRONMENT</title> - <para>The following environment variable affects the execution of the - allocation functions: - <variablelist> - <varlistentry> - <term><envar>MALLOC_CONF</envar></term> - - <listitem><para>If the environment variable - <envar>MALLOC_CONF</envar> is set, the characters it contains - will be interpreted as options.</para></listitem> - </varlistentry> - </variablelist> - </para> - </refsect1> - <refsect1 id="examples"> - <title>EXAMPLES</title> - <para>To dump core whenever a problem occurs: - <screen>ln -s 'abort:true' /etc/malloc.conf</screen> - </para> - <para>To specify in the source that only one arena should be automatically - created: - <programlisting language="C"><![CDATA[ -malloc_conf = "narenas:1";]]></programlisting></para> - </refsect1> - <refsect1 id="see_also"> - <title>SEE ALSO</title> - <para><citerefentry><refentrytitle>madvise</refentrytitle> - <manvolnum>2</manvolnum></citerefentry>, - <citerefentry><refentrytitle>mmap</refentrytitle> - <manvolnum>2</manvolnum></citerefentry>, - <citerefentry><refentrytitle>sbrk</refentrytitle> - <manvolnum>2</manvolnum></citerefentry>, - <citerefentry><refentrytitle>utrace</refentrytitle> - <manvolnum>2</manvolnum></citerefentry>, - <citerefentry><refentrytitle>alloca</refentrytitle> - <manvolnum>3</manvolnum></citerefentry>, - <citerefentry><refentrytitle>atexit</refentrytitle> - <manvolnum>3</manvolnum></citerefentry>, - <citerefentry><refentrytitle>getpagesize</refentrytitle> - <manvolnum>3</manvolnum></citerefentry></para> - </refsect1> - <refsect1 id="standards"> - <title>STANDARDS</title> - <para>The <function>malloc()</function>, - <function>calloc()</function>, - <function>realloc()</function>, and - <function>free()</function> functions conform to ISO/IEC - 9899:1990 (<quote>ISO C90</quote>).</para> - - <para>The <function>posix_memalign()</function> function conforms - to IEEE Std 1003.1-2001 (<quote>POSIX.1</quote>).</para> - </refsect1> - <refsect1 id="history"> - <title>HISTORY</title> - <para>The <function>malloc_usable_size()</function> and - <function>posix_memalign()</function> functions first appeared in FreeBSD - 7.0.</para> - - <para>The <function>aligned_alloc()</function>, - <function>malloc_stats_print()</function>, and - <function>mallctl*()</function> functions first appeared in FreeBSD - 10.0.</para> - - <para>The <function>*allocx()</function> functions first appeared in FreeBSD - 11.0.</para> - </refsect1> -</refentry> ->>>>>>> main diff --git a/contrib/jemalloc/include/jemalloc/internal/jemalloc_internal_defs.h.in b/contrib/jemalloc/include/jemalloc/internal/jemalloc_internal_defs.h.in index 52b31878a464..3588072f178c 100644 --- a/contrib/jemalloc/include/jemalloc/internal/jemalloc_internal_defs.h.in +++ b/contrib/jemalloc/include/jemalloc/internal/jemalloc_internal_defs.h.in @@ -1,4 +1,3 @@ -<<<<<<< HEAD #ifndef JEMALLOC_INTERNAL_DEFS_H_ #define JEMALLOC_INTERNAL_DEFS_H_ /* @@ -426,372 +425,3 @@ #undef JEMALLOC_ZERO_REALLOC_DEFAULT_FREE #endif /* JEMALLOC_INTERNAL_DEFS_H_ */ -||||||| dec341af7695 -======= -#ifndef JEMALLOC_INTERNAL_DEFS_H_ -#define JEMALLOC_INTERNAL_DEFS_H_ -/* - * If JEMALLOC_PREFIX is defined via --with-jemalloc-prefix, it will cause all - * public APIs to be prefixed. This makes it possible, with some care, to use - * multiple allocators simultaneously. - */ -#undef JEMALLOC_PREFIX -#undef JEMALLOC_CPREFIX - -/* - * Define overrides for non-standard allocator-related functions if they are - * present on the system. - */ -#undef JEMALLOC_OVERRIDE___LIBC_CALLOC -#undef JEMALLOC_OVERRIDE___LIBC_FREE -#undef JEMALLOC_OVERRIDE___LIBC_MALLOC -#undef JEMALLOC_OVERRIDE___LIBC_MEMALIGN -#undef JEMALLOC_OVERRIDE___LIBC_REALLOC -#undef JEMALLOC_OVERRIDE___LIBC_VALLOC -#undef JEMALLOC_OVERRIDE___POSIX_MEMALIGN - -/* - * JEMALLOC_PRIVATE_NAMESPACE is used as a prefix for all library-private APIs. - * For shared libraries, symbol visibility mechanisms prevent these symbols - * from being exported, but for static libraries, naming collisions are a real - * possibility. - */ -#undef JEMALLOC_PRIVATE_NAMESPACE - -/* - * Hyper-threaded CPUs may need a special instruction inside spin loops in - * order to yield to another virtual CPU. - */ -#undef CPU_SPINWAIT -/* 1 if CPU_SPINWAIT is defined, 0 otherwise. */ -#undef HAVE_CPU_SPINWAIT - -/* - * Number of significant bits in virtual addresses. This may be less than the - * total number of bits in a pointer, e.g. on x64, for which the uppermost 16 - * bits are the same as bit 47. - */ -#undef LG_VADDR - -/* Defined if C11 atomics are available. */ -#undef JEMALLOC_C11_ATOMICS - -/* Defined if GCC __atomic atomics are available. */ -#undef JEMALLOC_GCC_ATOMIC_ATOMICS -/* and the 8-bit variant support. */ -#undef JEMALLOC_GCC_U8_ATOMIC_ATOMICS - -/* Defined if GCC __sync atomics are available. */ -#undef JEMALLOC_GCC_SYNC_ATOMICS -/* and the 8-bit variant support. */ -#undef JEMALLOC_GCC_U8_SYNC_ATOMICS - -/* - * Defined if __builtin_clz() and __builtin_clzl() are available. - */ -#undef JEMALLOC_HAVE_BUILTIN_CLZ - -/* - * Defined if os_unfair_lock_*() functions are available, as provided by Darwin. - */ -#undef JEMALLOC_OS_UNFAIR_LOCK - -/* Defined if syscall(2) is usable. */ -#undef JEMALLOC_USE_SYSCALL - -/* - * Defined if secure_getenv(3) is available. - */ -#undef JEMALLOC_HAVE_SECURE_GETENV - -/* - * Defined if issetugid(2) is available. - */ -#undef JEMALLOC_HAVE_ISSETUGID - -/* Defined if pthread_atfork(3) is available. */ -#undef JEMALLOC_HAVE_PTHREAD_ATFORK - -/* Defined if pthread_setname_np(3) is available. */ -#undef JEMALLOC_HAVE_PTHREAD_SETNAME_NP - -/* - * 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 - * FreeBSD, pthread_key_create() allocates, which if used during malloc - * bootstrapping will cause recursion into the pthreads library. Therefore, if - * _malloc_thread_cleanup() exists, use it as the basis for thread cleanup in - * malloc_tsd. - */ -#undef JEMALLOC_MALLOC_THREAD_CLEANUP - -/* - * Defined if threaded initialization is known to be safe on this platform. - * Among other things, it must be possible to initialize a mutex without - * triggering allocation in order for threaded allocation to be safe. - */ -#undef JEMALLOC_THREADED_INIT - -/* - * Defined if the pthreads implementation defines - * _pthread_mutex_init_calloc_cb(), in which case the function is used in order - * to avoid recursive allocation during mutex initialization. - */ -#undef JEMALLOC_MUTEX_INIT_CB - -/* Non-empty if the tls_model attribute is supported. */ -#undef JEMALLOC_TLS_MODEL - -/* - * JEMALLOC_DEBUG enables assertions and other sanity checks, and disables - * inline functions. - */ -#undef JEMALLOC_DEBUG - -/* JEMALLOC_STATS enables statistics calculation. */ -#undef JEMALLOC_STATS - -/* JEMALLOC_EXPERIMENTAL_SMALLOCX_API enables experimental smallocx API. */ -#undef JEMALLOC_EXPERIMENTAL_SMALLOCX_API - -/* JEMALLOC_PROF enables allocation profiling. */ -#undef JEMALLOC_PROF - -/* Use libunwind for profile backtracing if defined. */ -#undef JEMALLOC_PROF_LIBUNWIND - -/* Use libgcc for profile backtracing if defined. */ -#undef JEMALLOC_PROF_LIBGCC - -/* Use gcc intrinsics for profile backtracing if defined. */ -#undef JEMALLOC_PROF_GCC - -/* - * JEMALLOC_DSS enables use of sbrk(2) to allocate extents from the data storage - * segment (DSS). - */ -#undef JEMALLOC_DSS - -/* Support memory filling (junk/zero). */ -#undef JEMALLOC_FILL - -/* Support utrace(2)-based tracing. */ -#undef JEMALLOC_UTRACE - -/* Support optional abort() on OOM. */ -#undef JEMALLOC_XMALLOC - -/* Support lazy locking (avoid locking unless a second thread is launched). */ -#undef JEMALLOC_LAZY_LOCK - -/* - * Minimum allocation alignment is 2^LG_QUANTUM bytes (ignoring tiny size - * classes). - */ -#undef LG_QUANTUM - -/* One page is 2^LG_PAGE bytes. */ -#undef LG_PAGE - -/* - * One huge page is 2^LG_HUGEPAGE bytes. Note that this is defined even if the - * system does not explicitly support huge pages; system calls that require - * explicit huge page support are separately configured. - */ -#undef LG_HUGEPAGE - -/* - * If defined, adjacent virtual memory mappings with identical attributes - * automatically coalesce, and they fragment when changes are made to subranges. - * This is the normal order of things for mmap()/munmap(), but on Windows - * VirtualAlloc()/VirtualFree() operations must be precisely matched, i.e. - * mappings do *not* coalesce/fragment. - */ -#undef JEMALLOC_MAPS_COALESCE - -/* - * If defined, retain memory for later reuse by default rather than using e.g. - * munmap() to unmap freed extents. This is enabled on 64-bit Linux because - * common sequences of mmap()/munmap() calls will cause virtual memory map - * holes. - */ -#undef JEMALLOC_RETAIN - -/* TLS is used to map arenas and magazine caches to threads. */ -#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, - * use ffs_*() from util.h. - */ -#undef JEMALLOC_INTERNAL_FFSLL -#undef JEMALLOC_INTERNAL_FFSL -#undef JEMALLOC_INTERNAL_FFS - -/* - * popcount*() functions to use for bitmapping. - */ -#undef JEMALLOC_INTERNAL_POPCOUNTL -#undef JEMALLOC_INTERNAL_POPCOUNT - -/* - * If defined, explicitly attempt to more uniformly distribute large allocation - * pointer alignments across all cache indices. - */ -#undef JEMALLOC_CACHE_OBLIVIOUS - -/* - * If defined, enable logging facilities. We make this a configure option to - * avoid taking extra branches everywhere. - */ -#undef JEMALLOC_LOG - -/* - * If defined, use readlinkat() (instead of readlink()) to follow - * /etc/malloc_conf. - */ -#undef JEMALLOC_READLINKAT - -/* - * Darwin (OS X) uses zones to work around Mach-O symbol override shortcomings. - */ -#undef JEMALLOC_ZONE - -/* - * Methods for determining whether the OS overcommits. - * JEMALLOC_PROC_SYS_VM_OVERCOMMIT_MEMORY: Linux's - * /proc/sys/vm.overcommit_memory file. - * JEMALLOC_SYSCTL_VM_OVERCOMMIT: FreeBSD's vm.overcommit sysctl. - */ -#undef JEMALLOC_SYSCTL_VM_OVERCOMMIT -#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. - * - * madvise(..., MADV_FREE) : This marks pages as being unused, such that they - * will be discarded rather than swapped out. - * madvise(..., MADV_DONTNEED) : If JEMALLOC_PURGE_MADVISE_DONTNEED_ZEROS is - * defined, this immediately discards pages, - * such that new pages will be demand-zeroed if - * the address region is later touched; - * otherwise this behaves similarly to - * MADV_FREE, though typically with higher - * system overhead. - */ -#undef JEMALLOC_PURGE_MADVISE_FREE -#undef JEMALLOC_PURGE_MADVISE_DONTNEED -#undef JEMALLOC_PURGE_MADVISE_DONTNEED_ZEROS - -/* Defined if madvise(2) is available but MADV_FREE is not (x86 Linux only). */ -#undef JEMALLOC_DEFINE_MADVISE_FREE - -/* - * Defined if MADV_DO[NT]DUMP is supported as an argument to madvise. - */ -#undef JEMALLOC_MADVISE_DONTDUMP - -/* - * Defined if transparent huge pages (THPs) are supported via the - * MADV_[NO]HUGEPAGE arguments to madvise(2), and THP support is enabled. - */ -#undef JEMALLOC_THP - -/* Define if operating system has alloca.h header. */ -#undef JEMALLOC_HAS_ALLOCA_H - -/* C99 restrict keyword supported. */ -#undef JEMALLOC_HAS_RESTRICT - -/* For use by hash code. */ -#undef JEMALLOC_BIG_ENDIAN - -/* sizeof(int) == 2^LG_SIZEOF_INT. */ -#undef LG_SIZEOF_INT - -/* sizeof(long) == 2^LG_SIZEOF_LONG. */ -#undef LG_SIZEOF_LONG - -/* sizeof(long long) == 2^LG_SIZEOF_LONG_LONG. */ -#undef LG_SIZEOF_LONG_LONG - -/* sizeof(intmax_t) == 2^LG_SIZEOF_INTMAX_T. */ -#undef LG_SIZEOF_INTMAX_T - -/* glibc malloc hooks (__malloc_hook, __realloc_hook, __free_hook). */ -#undef JEMALLOC_GLIBC_MALLOC_HOOK - -/* glibc memalign hook. */ -#undef JEMALLOC_GLIBC_MEMALIGN_HOOK - -/* pthread support */ -#undef JEMALLOC_HAVE_PTHREAD - -/* dlsym() support */ -#undef JEMALLOC_HAVE_DLSYM - -/* Adaptive mutex support in pthreads. */ -#undef JEMALLOC_HAVE_PTHREAD_MUTEX_ADAPTIVE_NP - -/* GNU specific sched_getcpu support */ -#undef JEMALLOC_HAVE_SCHED_GETCPU - -/* GNU specific sched_setaffinity support */ -#undef JEMALLOC_HAVE_SCHED_SETAFFINITY - -/* - * If defined, all the features necessary for background threads are present. - */ -#undef JEMALLOC_BACKGROUND_THREAD - -/* - * If defined, jemalloc symbols are not exported (doesn't work when - * JEMALLOC_PREFIX is not defined). - */ -#undef JEMALLOC_EXPORT - -/* config.malloc_conf options string. */ -#undef JEMALLOC_CONFIG_MALLOC_CONF - -/* If defined, jemalloc takes the malloc/free/etc. symbol names. */ -#undef JEMALLOC_IS_MALLOC - -/* - * Defined if strerror_r returns char * if _GNU_SOURCE is defined. - */ -#undef JEMALLOC_STRERROR_R_RETURNS_CHAR_WITH_GNU_SOURCE - -/* Performs additional safety checks when defined. */ -#undef JEMALLOC_OPT_SAFETY_CHECKS - -#endif /* JEMALLOC_INTERNAL_DEFS_H_ */ ->>>>>>> main diff --git a/contrib/jemalloc/include/jemalloc/internal/jemalloc_preamble.h.in b/contrib/jemalloc/include/jemalloc/internal/jemalloc_preamble.h.in index c4fb2d0793bf..e4932f1e8c18 100644 --- a/contrib/jemalloc/include/jemalloc/internal/jemalloc_preamble.h.in +++ b/contrib/jemalloc/include/jemalloc/internal/jemalloc_preamble.h.in @@ -1,4 +1,3 @@ -<<<<<<< HEAD #ifndef JEMALLOC_PREAMBLE_H #define JEMALLOC_PREAMBLE_H @@ -261,218 +260,3 @@ static const bool have_memcntl = ; #endif /* JEMALLOC_PREAMBLE_H */ -||||||| dec341af7695 -======= -#ifndef JEMALLOC_PREAMBLE_H -#define JEMALLOC_PREAMBLE_H - -#include "jemalloc_internal_defs.h" -#include "jemalloc/internal/jemalloc_internal_decls.h" - -#ifdef JEMALLOC_UTRACE -#include <sys/ktrace.h> -#endif - -#ifndef JEMALLOC_PRIVATE_NAMESPACE -#include "un-namespace.h" -#include "libc_private.h" -#endif - -#define JEMALLOC_NO_DEMANGLE -#ifdef JEMALLOC_JET -# undef JEMALLOC_IS_MALLOC -# define JEMALLOC_N(n) jet_##n -# include "jemalloc/internal/public_namespace.h" -# define JEMALLOC_NO_RENAME -# include "../jemalloc@install_suffix@.h" -# undef JEMALLOC_NO_RENAME -#else -# define JEMALLOC_N(n) @private_namespace@##n -# include "../jemalloc@install_suffix@.h" -#endif - -#if defined(JEMALLOC_OSATOMIC) -#include <libkern/OSAtomic.h> -#endif - -#ifdef JEMALLOC_ZONE -#include <mach/mach_error.h> -#include <mach/mach_init.h> -#include <mach/vm_map.h> -#endif - -#include "jemalloc/internal/jemalloc_internal_macros.h" - -/* - * Note that the ordering matters here; the hook itself is name-mangled. We - * want the inclusion of hooks to happen early, so that we hook as much as - * possible. - */ -#ifndef JEMALLOC_NO_PRIVATE_NAMESPACE -# ifndef JEMALLOC_JET -# include "jemalloc/internal/private_namespace.h" -# else -# include "jemalloc/internal/private_namespace_jet.h" -# endif -#endif -#include "jemalloc/internal/test_hooks.h" - -#ifdef JEMALLOC_DEFINE_MADVISE_FREE -# define JEMALLOC_MADV_FREE 8 -#endif - -static const bool config_debug = -#ifdef JEMALLOC_DEBUG - true -#else - false -#endif - ; -static const bool have_dss = -#ifdef JEMALLOC_DSS - true -#else - false -#endif - ; -static const bool have_madvise_huge = -#ifdef JEMALLOC_HAVE_MADVISE_HUGE - true -#else - false -#endif - ; -static const bool config_fill = -#ifdef JEMALLOC_FILL - true -#else - false -#endif - ; -static const bool config_lazy_lock = true; -static const char * const config_malloc_conf = JEMALLOC_CONFIG_MALLOC_CONF; -static const bool config_prof = -#ifdef JEMALLOC_PROF - true -#else - false -#endif - ; -static const bool config_prof_libgcc = -#ifdef JEMALLOC_PROF_LIBGCC - true -#else - false -#endif - ; -static const bool config_prof_libunwind = -#ifdef JEMALLOC_PROF_LIBUNWIND - true -#else - false -#endif - ; -static const bool maps_coalesce = -#ifdef JEMALLOC_MAPS_COALESCE - true -#else - false -#endif - ; -static const bool config_stats = -#ifdef JEMALLOC_STATS - true -#else - false -#endif - ; -static const bool config_tls = -#ifdef JEMALLOC_TLS - true -#else - false -#endif - ; -static const bool config_utrace = -#ifdef JEMALLOC_UTRACE - true -#else - false -#endif - ; -static const bool config_xmalloc = -#ifdef JEMALLOC_XMALLOC - true -#else - false -#endif - ; -static const bool config_cache_oblivious = -#ifdef JEMALLOC_CACHE_OBLIVIOUS - true -#else - false -#endif - ; -/* - * Undocumented, for jemalloc development use only at the moment. See the note - * in jemalloc/internal/log.h. - */ -static const bool config_log = -#ifdef JEMALLOC_LOG - true -#else - false -#endif - ; -/* - * Are extra safety checks enabled; things like checking the size of sized - * deallocations, double-frees, etc. - */ -static const bool config_opt_safety_checks = -#ifdef JEMALLOC_OPT_SAFETY_CHECKS - true -#elif defined(JEMALLOC_DEBUG) - /* - * This lets us only guard safety checks by one flag instead of two; fast - * checks can guard solely by config_opt_safety_checks and run in debug mode - * too. - */ - true -#else - false -#endif - ; - -#if defined(_WIN32) || defined(JEMALLOC_HAVE_SCHED_GETCPU) -/* Currently percpu_arena depends on sched_getcpu. */ -#define JEMALLOC_PERCPU_ARENA -#endif -static const bool have_percpu_arena = -#ifdef JEMALLOC_PERCPU_ARENA - true -#else - false -#endif - ; -/* - * Undocumented, and not recommended; the application should take full - * responsibility for tracking provenance. - */ -static const bool force_ivsalloc = -#ifdef JEMALLOC_FORCE_IVSALLOC - true -#else - false -#endif - ; -static const bool have_background_thread = -#ifdef JEMALLOC_BACKGROUND_THREAD - true -#else - false -#endif - ; - -#endif /* JEMALLOC_PREAMBLE_H */ ->>>>>>> main diff --git a/contrib/jemalloc/include/jemalloc/internal/tsd_win.h b/contrib/jemalloc/include/jemalloc/internal/tsd_win.h index 46be2434b5a5..a91dac88e06a 100644 --- a/contrib/jemalloc/include/jemalloc/internal/tsd_win.h +++ b/contrib/jemalloc/include/jemalloc/internal/tsd_win.h @@ -1,4 +1,3 @@ -<<<<<<< HEAD #ifdef JEMALLOC_INTERNAL_TSD_WIN_H #error This file should be included only once, by tsd.h. #endif @@ -138,145 +137,3 @@ tsd_set(tsd_t *val) { } wrapper->initialized = true; } -||||||| dec341af7695 -======= -#ifdef JEMALLOC_INTERNAL_TSD_WIN_H -#error This file should be included only once, by tsd.h. -#endif -#define JEMALLOC_INTERNAL_TSD_WIN_H - -typedef struct { - bool initialized; - tsd_t val; -} tsd_wrapper_t; - -extern DWORD tsd_tsd; -extern tsd_wrapper_t tsd_boot_wrapper; -extern bool tsd_booted; - -/* Initialization/cleanup. */ -JEMALLOC_ALWAYS_INLINE bool -tsd_cleanup_wrapper(void) { - DWORD error = GetLastError(); - tsd_wrapper_t *wrapper = (tsd_wrapper_t *)TlsGetValue(tsd_tsd); - SetLastError(error); - - if (wrapper == NULL) { - return false; - } - - if (wrapper->initialized) { - wrapper->initialized = false; - tsd_cleanup(&wrapper->val); - if (wrapper->initialized) { - /* Trigger another cleanup round. */ - return true; - } - } - malloc_tsd_dalloc(wrapper); - return false; -} - -JEMALLOC_ALWAYS_INLINE void -tsd_wrapper_set(tsd_wrapper_t *wrapper) { - if (!TlsSetValue(tsd_tsd, (void *)wrapper)) { - malloc_write("<jemalloc>: Error setting TSD\n"); - abort(); - } -} - -JEMALLOC_ALWAYS_INLINE tsd_wrapper_t * -tsd_wrapper_get(bool init) { - DWORD error = GetLastError(); - tsd_wrapper_t *wrapper = (tsd_wrapper_t *) TlsGetValue(tsd_tsd); - SetLastError(error); - - if (init && unlikely(wrapper == NULL)) { - wrapper = (tsd_wrapper_t *) - malloc_tsd_malloc(sizeof(tsd_wrapper_t)); - if (wrapper == NULL) { - malloc_write("<jemalloc>: Error allocating TSD\n"); - abort(); - } else { - wrapper->initialized = false; - /* MSVC is finicky about aggregate initialization. */ - tsd_t tsd_initializer = TSD_INITIALIZER; - wrapper->val = tsd_initializer; - } - tsd_wrapper_set(wrapper); - } - return wrapper; -} - -JEMALLOC_ALWAYS_INLINE bool -tsd_boot0(void) { - tsd_tsd = TlsAlloc(); - if (tsd_tsd == TLS_OUT_OF_INDEXES) { - return true; - } - malloc_tsd_cleanup_register(&tsd_cleanup_wrapper); - tsd_wrapper_set(&tsd_boot_wrapper); - tsd_booted = true; - return false; -} - -JEMALLOC_ALWAYS_INLINE void -tsd_boot1(void) { - tsd_wrapper_t *wrapper; - wrapper = (tsd_wrapper_t *) - malloc_tsd_malloc(sizeof(tsd_wrapper_t)); - if (wrapper == NULL) { - malloc_write("<jemalloc>: Error allocating TSD\n"); - abort(); - } - tsd_boot_wrapper.initialized = false; - tsd_cleanup(&tsd_boot_wrapper.val); - wrapper->initialized = false; - tsd_t initializer = TSD_INITIALIZER; - wrapper->val = initializer; - tsd_wrapper_set(wrapper); -} -JEMALLOC_ALWAYS_INLINE bool -tsd_boot(void) { - if (tsd_boot0()) { - return true; - } - tsd_boot1(); - return false; -} - -JEMALLOC_ALWAYS_INLINE bool -tsd_booted_get(void) { - return tsd_booted; -} - -JEMALLOC_ALWAYS_INLINE bool -tsd_get_allocates(void) { - return true; -} - -/* Get/set. */ -JEMALLOC_ALWAYS_INLINE tsd_t * -tsd_get(bool init) { - tsd_wrapper_t *wrapper; - - assert(tsd_booted); - wrapper = tsd_wrapper_get(init); - if (tsd_get_allocates() && !init && wrapper == NULL) { - return NULL; - } - return &wrapper->val; -} - -JEMALLOC_ALWAYS_INLINE void -tsd_set(tsd_t *val) { - tsd_wrapper_t *wrapper; - - assert(tsd_booted); - wrapper = tsd_wrapper_get(true); - if (likely(&wrapper->val != val)) { - wrapper->val = *(val); - } - wrapper->initialized = true; -} ->>>>>>> main diff --git a/contrib/jemalloc/include/jemalloc/jemalloc_defs.h.in b/contrib/jemalloc/include/jemalloc/jemalloc_defs.h.in index 19c990dcdbdf..cbe2fca6ba53 100644 --- a/contrib/jemalloc/include/jemalloc/jemalloc_defs.h.in +++ b/contrib/jemalloc/include/jemalloc/jemalloc_defs.h.in @@ -1,4 +1,3 @@ -<<<<<<< HEAD /* Defined if __attribute__((...)) syntax is supported. */ #undef JEMALLOC_HAVE_ATTR @@ -53,54 +52,3 @@ /* sizeof(void *) == 2^LG_SIZEOF_PTR. */ #undef LG_SIZEOF_PTR -||||||| dec341af7695 -======= -/* Defined if __attribute__((...)) syntax is supported. */ -#undef JEMALLOC_HAVE_ATTR - -/* Defined if alloc_size attribute is supported. */ -#undef JEMALLOC_HAVE_ATTR_ALLOC_SIZE - -/* Defined if format_arg(...) attribute is supported. */ -#undef JEMALLOC_HAVE_ATTR_FORMAT_ARG - -/* Defined if format(gnu_printf, ...) attribute is supported. */ -#undef JEMALLOC_HAVE_ATTR_FORMAT_GNU_PRINTF - -/* Defined if format(printf, ...) attribute is supported. */ -#undef JEMALLOC_HAVE_ATTR_FORMAT_PRINTF - -/* - * Define overrides for non-standard allocator-related functions if they are - * present on the system. - */ -#undef JEMALLOC_OVERRIDE_MEMALIGN -#undef JEMALLOC_OVERRIDE_VALLOC - -/* - * At least Linux omits the "const" in: - * - * size_t malloc_usable_size(const void *ptr); - * - * Match the operating system's prototype. - */ -#undef JEMALLOC_USABLE_SIZE_CONST - -/* - * If defined, specify throw() for the public function prototypes when compiling - * with C++. The only justification for this is to match the prototypes that - * glibc defines. - */ -#undef JEMALLOC_USE_CXX_THROW - -#ifdef _MSC_VER -# ifdef _WIN64 -# define LG_SIZEOF_PTR_WIN 3 -# else -# define LG_SIZEOF_PTR_WIN 2 -# endif -#endif - -/* sizeof(void *) == 2^LG_SIZEOF_PTR. */ -#undef LG_SIZEOF_PTR ->>>>>>> main diff --git a/contrib/jemalloc/include/jemalloc/jemalloc_macros.h.in b/contrib/jemalloc/include/jemalloc/jemalloc_macros.h.in index dc57f521f580..ebb3137e6f7e 100644 --- a/contrib/jemalloc/include/jemalloc/jemalloc_macros.h.in +++ b/contrib/jemalloc/include/jemalloc/jemalloc_macros.h.in @@ -1,4 +1,3 @@ -<<<<<<< HEAD #include <stdlib.h> #include <stdbool.h> #include <stdint.h> @@ -148,135 +147,3 @@ #else # define JEMALLOC_SYS_NOTHROW JEMALLOC_NOTHROW #endif -||||||| dec341af7695 -======= -#include <stdlib.h> -#include <stdbool.h> -#include <stdint.h> -#include <limits.h> -#include <strings.h> - -#define JEMALLOC_VERSION "@jemalloc_version@" -#define JEMALLOC_VERSION_MAJOR @jemalloc_version_major@ -#define JEMALLOC_VERSION_MINOR @jemalloc_version_minor@ -#define JEMALLOC_VERSION_BUGFIX @jemalloc_version_bugfix@ -#define JEMALLOC_VERSION_NREV @jemalloc_version_nrev@ -#define JEMALLOC_VERSION_GID "@jemalloc_version_gid@" -#define JEMALLOC_VERSION_GID_IDENT @jemalloc_version_gid@ - -#define MALLOCX_LG_ALIGN(la) ((int)(la)) -#if LG_SIZEOF_PTR == 2 -# define MALLOCX_ALIGN(a) ((int)(ffs((int)(a))-1)) -#else -# define MALLOCX_ALIGN(a) \ - ((int)(((size_t)(a) < (size_t)INT_MAX) ? ffs((int)(a))-1 : \ - ffs((int)(((size_t)(a))>>32))+31)) -#endif -#define MALLOCX_ZERO ((int)0x40) -/* - * Bias tcache index bits so that 0 encodes "automatic tcache management", and 1 - * encodes MALLOCX_TCACHE_NONE. - */ -#define MALLOCX_TCACHE(tc) ((int)(((tc)+2) << 8)) -#define MALLOCX_TCACHE_NONE MALLOCX_TCACHE(-1) -/* - * Bias arena index bits so that 0 encodes "use an automatically chosen arena". - */ -#define MALLOCX_ARENA(a) ((((int)(a))+1) << 20) - -/* - * Use as arena index in "arena.<i>.{purge,decay,dss}" and - * "stats.arenas.<i>.*" mallctl interfaces to select all arenas. This - * definition is intentionally specified in raw decimal format to support - * cpp-based string concatenation, e.g. - * - * #define STRINGIFY_HELPER(x) #x - * #define STRINGIFY(x) STRINGIFY_HELPER(x) - * - * mallctl("arena." STRINGIFY(MALLCTL_ARENAS_ALL) ".purge", NULL, NULL, NULL, - * 0); - */ -#define MALLCTL_ARENAS_ALL 4096 -/* - * Use as arena index in "stats.arenas.<i>.*" mallctl interfaces to select - * destroyed arenas. - */ -#define MALLCTL_ARENAS_DESTROYED 4097 - -#if defined(__cplusplus) && defined(JEMALLOC_USE_CXX_THROW) -# define JEMALLOC_CXX_THROW throw() -#else -# define JEMALLOC_CXX_THROW -#endif - -#if defined(_MSC_VER) -# define JEMALLOC_ATTR(s) -# define JEMALLOC_ALIGNED(s) __declspec(align(s)) -# define JEMALLOC_ALLOC_SIZE(s) -# define JEMALLOC_ALLOC_SIZE2(s1, s2) -# ifndef JEMALLOC_EXPORT -# ifdef DLLEXPORT -# define JEMALLOC_EXPORT __declspec(dllexport) -# else -# define JEMALLOC_EXPORT __declspec(dllimport) -# endif -# endif -# define JEMALLOC_FORMAT_ARG(i) -# define JEMALLOC_FORMAT_PRINTF(s, i) -# define JEMALLOC_NOINLINE __declspec(noinline) -# ifdef __cplusplus -# define JEMALLOC_NOTHROW __declspec(nothrow) -# else -# define JEMALLOC_NOTHROW -# endif -# define JEMALLOC_SECTION(s) __declspec(allocate(s)) -# define JEMALLOC_RESTRICT_RETURN __declspec(restrict) -# if _MSC_VER >= 1900 && !defined(__EDG__) -# define JEMALLOC_ALLOCATOR __declspec(allocator) -# else -# define JEMALLOC_ALLOCATOR -# endif -#elif defined(JEMALLOC_HAVE_ATTR) -# define JEMALLOC_ATTR(s) __attribute__((s)) -# define JEMALLOC_ALIGNED(s) JEMALLOC_ATTR(aligned(s)) -# ifdef JEMALLOC_HAVE_ATTR_ALLOC_SIZE -# define JEMALLOC_ALLOC_SIZE(s) JEMALLOC_ATTR(alloc_size(s)) -# define JEMALLOC_ALLOC_SIZE2(s1, s2) JEMALLOC_ATTR(alloc_size(s1, s2)) -# else -# define JEMALLOC_ALLOC_SIZE(s) -# define JEMALLOC_ALLOC_SIZE2(s1, s2) -# endif -# ifndef JEMALLOC_EXPORT -# define JEMALLOC_EXPORT JEMALLOC_ATTR(visibility("default")) -# endif -# ifdef JEMALLOC_HAVE_ATTR_FORMAT_ARG -# define JEMALLOC_FORMAT_ARG(i) JEMALLOC_ATTR(__format_arg__(3)) -# else -# define JEMALLOC_FORMAT_ARG(i) -# endif -# ifdef JEMALLOC_HAVE_ATTR_FORMAT_GNU_PRINTF -# define JEMALLOC_FORMAT_PRINTF(s, i) JEMALLOC_ATTR(format(gnu_printf, s, i)) -# elif defined(JEMALLOC_HAVE_ATTR_FORMAT_PRINTF) -# define JEMALLOC_FORMAT_PRINTF(s, i) JEMALLOC_ATTR(format(printf, s, i)) -# else -# define JEMALLOC_FORMAT_PRINTF(s, i) -# endif -# define JEMALLOC_NOINLINE JEMALLOC_ATTR(noinline) -# define JEMALLOC_NOTHROW JEMALLOC_ATTR(nothrow) -# define JEMALLOC_SECTION(s) JEMALLOC_ATTR(section(s)) -# define JEMALLOC_RESTRICT_RETURN -# define JEMALLOC_ALLOCATOR -#else -# define JEMALLOC_ATTR(s) -# define JEMALLOC_ALIGNED(s) -# define JEMALLOC_ALLOC_SIZE(s) -# define JEMALLOC_ALLOC_SIZE2(s1, s2) -# define JEMALLOC_EXPORT -# define JEMALLOC_FORMAT_PRINTF(s, i) -# define JEMALLOC_NOINLINE -# define JEMALLOC_NOTHROW -# define JEMALLOC_SECTION(s) -# define JEMALLOC_RESTRICT_RETURN -# define JEMALLOC_ALLOCATOR -#endif ->>>>>>> main diff --git a/contrib/jemalloc/include/jemalloc/jemalloc_protos.h.in b/contrib/jemalloc/include/jemalloc/jemalloc_protos.h.in index 116ef116b4e1..356221cc8d52 100644 --- a/contrib/jemalloc/include/jemalloc/jemalloc_protos.h.in +++ b/contrib/jemalloc/include/jemalloc/jemalloc_protos.h.in @@ -1,4 +1,3 @@ -<<<<<<< HEAD /* * The @je_@ prefix on the following public symbol declarations is an artifact * of namespace management, and should be omitted in application code unless @@ -70,72 +69,3 @@ JEMALLOC_EXPORT JEMALLOC_ALLOCATOR JEMALLOC_RESTRICT_RETURN void JEMALLOC_SYS_NOTHROW *@je_@valloc(size_t size) JEMALLOC_CXX_THROW JEMALLOC_ATTR(malloc); #endif -||||||| dec341af7695 -======= -/* - * The @je_@ prefix on the following public symbol declarations is an artifact - * of namespace management, and should be omitted in application code unless - * JEMALLOC_NO_DEMANGLE is defined (see jemalloc_mangle@install_suffix@.h). - */ -extern JEMALLOC_EXPORT const char *@je_@malloc_conf; -extern JEMALLOC_EXPORT void (*@je_@malloc_message)(void *cbopaque, - const char *s); - -JEMALLOC_EXPORT JEMALLOC_ALLOCATOR JEMALLOC_RESTRICT_RETURN - void JEMALLOC_NOTHROW *@je_@malloc(size_t size) - JEMALLOC_CXX_THROW JEMALLOC_ATTR(malloc) JEMALLOC_ALLOC_SIZE(1); -JEMALLOC_EXPORT JEMALLOC_ALLOCATOR JEMALLOC_RESTRICT_RETURN - void JEMALLOC_NOTHROW *@je_@calloc(size_t num, size_t size) - JEMALLOC_CXX_THROW JEMALLOC_ATTR(malloc) JEMALLOC_ALLOC_SIZE2(1, 2); -JEMALLOC_EXPORT int JEMALLOC_NOTHROW @je_@posix_memalign(void **memptr, - size_t alignment, size_t size) JEMALLOC_CXX_THROW JEMALLOC_ATTR(nonnull(1)); -JEMALLOC_EXPORT JEMALLOC_ALLOCATOR JEMALLOC_RESTRICT_RETURN - void JEMALLOC_NOTHROW *@je_@aligned_alloc(size_t alignment, - size_t size) JEMALLOC_CXX_THROW JEMALLOC_ATTR(malloc) - JEMALLOC_ALLOC_SIZE(2); -JEMALLOC_EXPORT JEMALLOC_ALLOCATOR JEMALLOC_RESTRICT_RETURN - void JEMALLOC_NOTHROW *@je_@realloc(void *ptr, size_t size) - JEMALLOC_CXX_THROW JEMALLOC_ALLOC_SIZE(2); -JEMALLOC_EXPORT void JEMALLOC_NOTHROW @je_@free(void *ptr) - JEMALLOC_CXX_THROW; - -JEMALLOC_EXPORT JEMALLOC_ALLOCATOR JEMALLOC_RESTRICT_RETURN - void JEMALLOC_NOTHROW *@je_@mallocx(size_t size, int flags) - JEMALLOC_ATTR(malloc) JEMALLOC_ALLOC_SIZE(1); -JEMALLOC_EXPORT JEMALLOC_ALLOCATOR JEMALLOC_RESTRICT_RETURN - void JEMALLOC_NOTHROW *@je_@rallocx(void *ptr, size_t size, - int flags) JEMALLOC_ALLOC_SIZE(2); -JEMALLOC_EXPORT size_t JEMALLOC_NOTHROW @je_@xallocx(void *ptr, size_t size, - size_t extra, int flags); -JEMALLOC_EXPORT size_t JEMALLOC_NOTHROW @je_@sallocx(const void *ptr, - int flags) JEMALLOC_ATTR(pure); -JEMALLOC_EXPORT void JEMALLOC_NOTHROW @je_@dallocx(void *ptr, int flags); -JEMALLOC_EXPORT void JEMALLOC_NOTHROW @je_@sdallocx(void *ptr, size_t size, - int flags); -JEMALLOC_EXPORT size_t JEMALLOC_NOTHROW @je_@nallocx(size_t size, int flags) - JEMALLOC_ATTR(pure); - -JEMALLOC_EXPORT int JEMALLOC_NOTHROW @je_@mallctl(const char *name, - void *oldp, size_t *oldlenp, void *newp, size_t newlen); -JEMALLOC_EXPORT int JEMALLOC_NOTHROW @je_@mallctlnametomib(const char *name, - size_t *mibp, size_t *miblenp); -JEMALLOC_EXPORT int JEMALLOC_NOTHROW @je_@mallctlbymib(const size_t *mib, - size_t miblen, void *oldp, size_t *oldlenp, void *newp, size_t newlen); -JEMALLOC_EXPORT void JEMALLOC_NOTHROW @je_@malloc_stats_print( - void (*write_cb)(void *, const char *), void *@je_@cbopaque, - const char *opts); -JEMALLOC_EXPORT size_t JEMALLOC_NOTHROW @je_@malloc_usable_size( - JEMALLOC_USABLE_SIZE_CONST void *ptr) JEMALLOC_CXX_THROW; - -#ifdef JEMALLOC_OVERRIDE_MEMALIGN -JEMALLOC_EXPORT JEMALLOC_ALLOCATOR JEMALLOC_RESTRICT_RETURN - void JEMALLOC_NOTHROW *@je_@memalign(size_t alignment, size_t size) - JEMALLOC_CXX_THROW JEMALLOC_ATTR(malloc); -#endif - -#ifdef JEMALLOC_OVERRIDE_VALLOC -JEMALLOC_EXPORT JEMALLOC_ALLOCATOR JEMALLOC_RESTRICT_RETURN - void JEMALLOC_NOTHROW *@je_@valloc(size_t size) JEMALLOC_CXX_THROW - JEMALLOC_ATTR(malloc); -#endif ->>>>>>> main diff --git a/contrib/jemalloc/m4/ax_cxx_compile_stdcxx.m4 b/contrib/jemalloc/m4/ax_cxx_compile_stdcxx.m4 index 72784472d275..43087b2e6889 100644 --- a/contrib/jemalloc/m4/ax_cxx_compile_stdcxx.m4 +++ b/contrib/jemalloc/m4/ax_cxx_compile_stdcxx.m4 @@ -1,4 +1,3 @@ -<<<<<<< HEAD # =========================================================================== # https://www.gnu.org/software/autoconf-archive/ax_cxx_compile_stdcxx.html # =========================================================================== @@ -950,568 +949,3 @@ namespace cxx17 #endif // __cplusplus < 201703L ]]) -||||||| dec341af7695 -======= -# =========================================================================== -# http://www.gnu.org/software/autoconf-archive/ax_cxx_compile_stdcxx.html -# =========================================================================== -# -# SYNOPSIS -# -# AX_CXX_COMPILE_STDCXX(VERSION, [ext|noext], [mandatory|optional]) -# -# DESCRIPTION -# -# Check for baseline language coverage in the compiler for the specified -# version of the C++ standard. If necessary, add switches to CXX and -# CXXCPP to enable support. VERSION may be '11' (for the C++11 standard) -# or '14' (for the C++14 standard). -# -# The second argument, if specified, indicates whether you insist on an -# extended mode (e.g. -std=gnu++11) or a strict conformance mode (e.g. -# -std=c++11). If neither is specified, you get whatever works, with -# preference for an extended mode. -# -# The third argument, if specified 'mandatory' or if left unspecified, -# indicates that baseline support for the specified C++ standard is -# required and that the macro should error out if no mode with that -# support is found. If specified 'optional', then configuration proceeds -# regardless, after defining HAVE_CXX${VERSION} if and only if a -# supporting mode is found. -# -# LICENSE -# -# Copyright (c) 2008 Benjamin Kosnik <bkoz@redhat.com> -# Copyright (c) 2012 Zack Weinberg <zackw@panix.com> -# Copyright (c) 2013 Roy Stogner <roystgnr@ices.utexas.edu> -# Copyright (c) 2014, 2015 Google Inc.; contributed by Alexey Sokolov <sokolov@google.com> -# Copyright (c) 2015 Paul Norman <penorman@mac.com> -# Copyright (c) 2015 Moritz Klammler <moritz@klammler.eu> -# -# Copying and distribution of this file, with or without modification, are -# permitted in any medium without royalty provided the copyright notice -# and this notice are preserved. This file is offered as-is, without any -# warranty. - -#serial 4 - -dnl This macro is based on the code from the AX_CXX_COMPILE_STDCXX_11 macro -dnl (serial version number 13). - -AC_DEFUN([AX_CXX_COMPILE_STDCXX], [dnl - m4_if([$1], [11], [], - [$1], [14], [], - [$1], [17], [m4_fatal([support for C++17 not yet implemented in AX_CXX_COMPILE_STDCXX])], - [m4_fatal([invalid first argument `$1' to AX_CXX_COMPILE_STDCXX])])dnl - m4_if([$2], [], [], - [$2], [ext], [], - [$2], [noext], [], - [m4_fatal([invalid second argument `$2' to AX_CXX_COMPILE_STDCXX])])dnl - m4_if([$3], [], [ax_cxx_compile_cxx$1_required=true], - [$3], [mandatory], [ax_cxx_compile_cxx$1_required=true], - [$3], [optional], [ax_cxx_compile_cxx$1_required=false], - [m4_fatal([invalid third argument `$3' to AX_CXX_COMPILE_STDCXX])]) - AC_LANG_PUSH([C++])dnl - ac_success=no - AC_CACHE_CHECK(whether $CXX supports C++$1 features by default, - ax_cv_cxx_compile_cxx$1, - [AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_testbody_$1])], - [ax_cv_cxx_compile_cxx$1=yes], - [ax_cv_cxx_compile_cxx$1=no])]) - if test x$ax_cv_cxx_compile_cxx$1 = xyes; then - ac_success=yes - fi - - m4_if([$2], [noext], [], [dnl - if test x$ac_success = xno; then - for switch in -std=gnu++$1 -std=gnu++0x; do - cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx$1_$switch]) - AC_CACHE_CHECK(whether $CXX supports C++$1 features with $switch, - $cachevar, - [ac_save_CXX="$CXX" - CXX="$CXX $switch" - AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_testbody_$1])], - [eval $cachevar=yes], - [eval $cachevar=no]) - CXX="$ac_save_CXX"]) - if eval test x\$$cachevar = xyes; then - CXX="$CXX $switch" - if test -n "$CXXCPP" ; then - CXXCPP="$CXXCPP $switch" - fi - ac_success=yes - break - fi - done - fi]) - - m4_if([$2], [ext], [], [dnl - if test x$ac_success = xno; then - dnl HP's aCC needs +std=c++11 according to: - dnl http://h21007.www2.hp.com/portal/download/files/unprot/aCxx/PDF_Release_Notes/769149-001.pdf - dnl Cray's crayCC needs "-h std=c++11" - for switch in -std=c++$1 -std=c++0x +std=c++$1 "-h std=c++$1"; do - cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx$1_$switch]) - AC_CACHE_CHECK(whether $CXX supports C++$1 features with $switch, - $cachevar, - [ac_save_CXX="$CXX" - CXX="$CXX $switch" - AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_testbody_$1])], - [eval $cachevar=yes], - [eval $cachevar=no]) - CXX="$ac_save_CXX"]) - if eval test x\$$cachevar = xyes; then - CXX="$CXX $switch" - if test -n "$CXXCPP" ; then - CXXCPP="$CXXCPP $switch" - fi - ac_success=yes - break - fi - done - fi]) - AC_LANG_POP([C++]) - if test x$ax_cxx_compile_cxx$1_required = xtrue; then - if test x$ac_success = xno; then - AC_MSG_ERROR([*** A compiler with support for C++$1 language features is required.]) - fi - fi - if test x$ac_success = xno; then - HAVE_CXX$1=0 - AC_MSG_NOTICE([No compiler with C++$1 support was found]) - else - HAVE_CXX$1=1 - AC_DEFINE(HAVE_CXX$1,1, - [define if the compiler supports basic C++$1 syntax]) - fi - AC_SUBST(HAVE_CXX$1) -]) - - -dnl Test body for checking C++11 support - -m4_define([_AX_CXX_COMPILE_STDCXX_testbody_11], - _AX_CXX_COMPILE_STDCXX_testbody_new_in_11 -) - - -dnl Test body for checking C++14 support - -m4_define([_AX_CXX_COMPILE_STDCXX_testbody_14], - _AX_CXX_COMPILE_STDCXX_testbody_new_in_11 - _AX_CXX_COMPILE_STDCXX_testbody_new_in_14 -) - - -dnl Tests for new features in C++11 - -m4_define([_AX_CXX_COMPILE_STDCXX_testbody_new_in_11], [[ - -// If the compiler admits that it is not ready for C++11, why torture it? -// Hopefully, this will speed up the test. - -#ifndef __cplusplus - -#error "This is not a C++ compiler" - -#elif __cplusplus < 201103L - -#error "This is not a C++11 compiler" - -#else - -namespace cxx11 -{ - - namespace test_static_assert - { - - template <typename T> - struct check - { - static_assert(sizeof(int) <= sizeof(T), "not big enough"); - }; - - } - - namespace test_final_override - { - - struct Base - { - virtual void f() {} - }; - - struct Derived : public Base - { - virtual void f() override {} - }; - - } - - namespace test_double_right_angle_brackets - { - - template < typename T > - struct check {}; - - typedef check<void> single_type; - typedef check<check<void>> double_type; - typedef check<check<check<void>>> triple_type; - typedef check<check<check<check<void>>>> quadruple_type; - - } - - namespace test_decltype - { - - int - f() - { - int a = 1; - decltype(a) b = 2; - return a + b; - } - - } - - namespace test_type_deduction - { - - template < typename T1, typename T2 > - struct is_same - { - static const bool value = false; - }; - - template < typename T > - struct is_same<T, T> - { - static const bool value = true; - }; - - template < typename T1, typename T2 > - auto - add(T1 a1, T2 a2) -> decltype(a1 + a2) - { - return a1 + a2; - } - - int - test(const int c, volatile int v) - { - static_assert(is_same<int, decltype(0)>::value == true, ""); - static_assert(is_same<int, decltype(c)>::value == false, ""); - static_assert(is_same<int, decltype(v)>::value == false, ""); - auto ac = c; - auto av = v; - auto sumi = ac + av + 'x'; - auto sumf = ac + av + 1.0; - static_assert(is_same<int, decltype(ac)>::value == true, ""); - static_assert(is_same<int, decltype(av)>::value == true, ""); - static_assert(is_same<int, decltype(sumi)>::value == true, ""); - static_assert(is_same<int, decltype(sumf)>::value == false, ""); - static_assert(is_same<int, decltype(add(c, v))>::value == true, ""); - return (sumf > 0.0) ? sumi : add(c, v); - } - - } - - namespace test_noexcept - { - - int f() { return 0; } - int g() noexcept { return 0; } - - static_assert(noexcept(f()) == false, ""); - static_assert(noexcept(g()) == true, ""); - - } - - namespace test_constexpr - { - - template < typename CharT > - unsigned long constexpr - strlen_c_r(const CharT *const s, const unsigned long acc) noexcept - { - return *s ? strlen_c_r(s + 1, acc + 1) : acc; - } - - template < typename CharT > - unsigned long constexpr - strlen_c(const CharT *const s) noexcept - { - return strlen_c_r(s, 0UL); - } - - static_assert(strlen_c("") == 0UL, ""); - static_assert(strlen_c("1") == 1UL, ""); - static_assert(strlen_c("example") == 7UL, ""); - static_assert(strlen_c("another\0example") == 7UL, ""); - - } - - namespace test_rvalue_references - { - - template < int N > - struct answer - { - static constexpr int value = N; - }; - - answer<1> f(int&) { return answer<1>(); } - answer<2> f(const int&) { return answer<2>(); } - answer<3> f(int&&) { return answer<3>(); } - - void - test() - { - int i = 0; - const int c = 0; - static_assert(decltype(f(i))::value == 1, ""); - static_assert(decltype(f(c))::value == 2, ""); - static_assert(decltype(f(0))::value == 3, ""); - } - - } - - namespace test_uniform_initialization - { - - struct test - { - static const int zero {}; - static const int one {1}; - }; - - static_assert(test::zero == 0, ""); - static_assert(test::one == 1, ""); - - } - - namespace test_lambdas - { - - void - test1() - { - auto lambda1 = [](){}; - auto lambda2 = lambda1; - lambda1(); - lambda2(); - } - - int - test2() - { - auto a = [](int i, int j){ return i + j; }(1, 2); - auto b = []() -> int { return '0'; }(); - auto c = [=](){ return a + b; }(); - auto d = [&](){ return c; }(); - auto e = [a, &b](int x) mutable { - const auto identity = [](int y){ return y; }; - for (auto i = 0; i < a; ++i) - a += b--; - return x + identity(a + b); - }(0); - return a + b + c + d + e; - } - - int - test3() - { - const auto nullary = [](){ return 0; }; - const auto unary = [](int x){ return x; }; - using nullary_t = decltype(nullary); - using unary_t = decltype(unary); - const auto higher1st = [](nullary_t f){ return f(); }; - const auto higher2nd = [unary](nullary_t f1){ - return [unary, f1](unary_t f2){ return f2(unary(f1())); }; - }; - return higher1st(nullary) + higher2nd(nullary)(unary); - } - - } - - namespace test_variadic_templates - { - - template <int...> - struct sum; - - template <int N0, int... N1toN> - struct sum<N0, N1toN...> - { - static constexpr auto value = N0 + sum<N1toN...>::value; - }; - - template <> - struct sum<> - { - static constexpr auto value = 0; - }; - - static_assert(sum<>::value == 0, ""); - static_assert(sum<1>::value == 1, ""); - static_assert(sum<23>::value == 23, ""); - static_assert(sum<1, 2>::value == 3, ""); - static_assert(sum<5, 5, 11>::value == 21, ""); - static_assert(sum<2, 3, 5, 7, 11, 13>::value == 41, ""); - - } - - // http://stackoverflow.com/questions/13728184/template-aliases-and-sfinae - // Clang 3.1 fails with headers of libstd++ 4.8.3 when using std::function - // because of this. - namespace test_template_alias_sfinae - { - - struct foo {}; - - template<typename T> - using member = typename T::member_type; - - template<typename T> - void func(...) {} - - template<typename T> - void func(member<T>*) {} - - void test(); - - void test() { func<foo>(0); } - - } - -} // namespace cxx11 - -#endif // __cplusplus >= 201103L - -]]) - - -dnl Tests for new features in C++14 - -m4_define([_AX_CXX_COMPILE_STDCXX_testbody_new_in_14], [[ - -// If the compiler admits that it is not ready for C++14, why torture it? -// Hopefully, this will speed up the test. - -#ifndef __cplusplus - -#error "This is not a C++ compiler" - -#elif __cplusplus < 201402L - -#error "This is not a C++14 compiler" - -#else - -namespace cxx14 -{ - - namespace test_polymorphic_lambdas - { - - int - test() - { - const auto lambda = [](auto&&... args){ - const auto istiny = [](auto x){ - return (sizeof(x) == 1UL) ? 1 : 0; - }; - const int aretiny[] = { istiny(args)... }; - return aretiny[0]; - }; - return lambda(1, 1L, 1.0f, '1'); - } - - } - - namespace test_binary_literals - { - - constexpr auto ivii = 0b0000000000101010; - static_assert(ivii == 42, "wrong value"); - - } - - namespace test_generalized_constexpr - { - - template < typename CharT > - constexpr unsigned long - strlen_c(const CharT *const s) noexcept - { - auto length = 0UL; - for (auto p = s; *p; ++p) - ++length; - return length; - } - - static_assert(strlen_c("") == 0UL, ""); - static_assert(strlen_c("x") == 1UL, ""); - static_assert(strlen_c("test") == 4UL, ""); - static_assert(strlen_c("another\0test") == 7UL, ""); - - } - - namespace test_lambda_init_capture - { - - int - test() - { - auto x = 0; - const auto lambda1 = [a = x](int b){ return a + b; }; - const auto lambda2 = [a = lambda1(x)](){ return a; }; - return lambda2(); - } - - } - - namespace test_digit_seperators - { - - constexpr auto ten_million = 100'000'000; - static_assert(ten_million == 100000000, ""); - - } - - namespace test_return_type_deduction - { - - auto f(int& x) { return x; } - decltype(auto) g(int& x) { return x; } - - template < typename T1, typename T2 > - struct is_same - { - static constexpr auto value = false; - }; - - template < typename T > - struct is_same<T, T> - { - static constexpr auto value = true; - }; - - int - test() - { - auto x = 0; - static_assert(is_same<int, decltype(f(x))>::value, ""); - static_assert(is_same<int&, decltype(g(x))>::value, ""); - return x; - } - - } - -} // namespace cxx14 - -#endif // __cplusplus >= 201402L - -]]) ->>>>>>> main diff --git a/contrib/jemalloc/scripts/gen_run_tests.py b/contrib/jemalloc/scripts/gen_run_tests.py index 698d3bce4bbf..7c3075f9f6a6 100755 --- a/contrib/jemalloc/scripts/gen_run_tests.py +++ b/contrib/jemalloc/scripts/gen_run_tests.py @@ -1,4 +1,3 @@ -<<<<<<< HEAD #!/usr/bin/env python3 import sys @@ -129,132 +128,3 @@ chmod 755 run_test_%(ind)d.sh""" % {'ind': ind, 'config_line': config_line, print('for i in `seq 0 %(last_ind)d` ; do echo run_test_${i}.sh ; done | xargs' ' -P %(nparallel)d -n 1 sh' % {'last_ind': ind-1, 'nparallel': nparallel}) -||||||| dec341af7695 -======= -#!/usr/bin/env python - -import sys -from itertools import combinations -from os import uname -from multiprocessing import cpu_count -from subprocess import call - -# Later, we want to test extended vaddr support. Apparently, the "real" way of -# checking this is flaky on OS X. -bits_64 = sys.maxsize > 2**32 - -nparallel = cpu_count() * 2 - -uname = uname()[0] - -if "BSD" in uname: - make_cmd = 'gmake' -else: - make_cmd = 'make' - -def powerset(items): - result = [] - for i in xrange(len(items) + 1): - result += combinations(items, i) - return result - -possible_compilers = [] -for cc, cxx in (['gcc', 'g++'], ['clang', 'clang++']): - try: - cmd_ret = call([cc, "-v"]) - if cmd_ret == 0: - possible_compilers.append((cc, cxx)) - except: - pass -possible_compiler_opts = [ - '-m32', -] -possible_config_opts = [ - '--enable-debug', - '--enable-prof', - '--disable-stats', - '--enable-opt-safety-checks', -] -if bits_64: - possible_config_opts.append('--with-lg-vaddr=56') - -possible_malloc_conf_opts = [ - 'tcache:false', - 'dss:primary', - 'percpu_arena:percpu', - 'background_thread:true', -] - -print 'set -e' -print 'if [ -f Makefile ] ; then %(make_cmd)s relclean ; fi' % {'make_cmd': make_cmd} -print 'autoconf' -print 'rm -rf run_tests.out' -print 'mkdir run_tests.out' -print 'cd run_tests.out' - -ind = 0 -for cc, cxx in possible_compilers: - for compiler_opts in powerset(possible_compiler_opts): - for config_opts in powerset(possible_config_opts): - for malloc_conf_opts in powerset(possible_malloc_conf_opts): - if cc is 'clang' \ - and '-m32' in possible_compiler_opts \ - and '--enable-prof' in config_opts: - continue - config_line = ( - 'EXTRA_CFLAGS=-Werror EXTRA_CXXFLAGS=-Werror ' - + 'CC="{} {}" '.format(cc, " ".join(compiler_opts)) - + 'CXX="{} {}" '.format(cxx, " ".join(compiler_opts)) - + '../../configure ' - + " ".join(config_opts) + (' --with-malloc-conf=' + - ",".join(malloc_conf_opts) if len(malloc_conf_opts) > 0 - else '') - ) - - # We don't want to test large vaddr spaces in 32-bit mode. - if ('-m32' in compiler_opts and '--with-lg-vaddr=56' in - config_opts): - continue - - # Per CPU arenas are only supported on Linux. - linux_supported = ('percpu_arena:percpu' in malloc_conf_opts \ - or 'background_thread:true' in malloc_conf_opts) - # Heap profiling and dss are not supported on OS X. - darwin_unsupported = ('--enable-prof' in config_opts or \ - 'dss:primary' in malloc_conf_opts) - if (uname == 'Linux' and linux_supported) \ - or (not linux_supported and (uname != 'Darwin' or \ - not darwin_unsupported)): - print """cat <<EOF > run_test_%(ind)d.sh -#!/bin/sh - -set -e - -abort() { - echo "==> Error" >> run_test.log - echo "Error; see run_tests.out/run_test_%(ind)d.out/run_test.log" - exit 255 # Special exit code tells xargs to terminate. -} - -# Environment variables are not supported. -run_cmd() { - echo "==> \$@" >> run_test.log - \$@ >> run_test.log 2>&1 || abort -} - -echo "=> run_test_%(ind)d: %(config_line)s" -mkdir run_test_%(ind)d.out -cd run_test_%(ind)d.out - -echo "==> %(config_line)s" >> run_test.log -%(config_line)s >> run_test.log 2>&1 || abort - -run_cmd %(make_cmd)s all tests -run_cmd %(make_cmd)s check -run_cmd %(make_cmd)s distclean -EOF -chmod 755 run_test_%(ind)d.sh""" % {'ind': ind, 'config_line': config_line, 'make_cmd': make_cmd} - ind += 1 - -print 'for i in `seq 0 %(last_ind)d` ; do echo run_test_${i}.sh ; done | xargs -P %(nparallel)d -n 1 sh' % {'last_ind': ind-1, 'nparallel': nparallel} ->>>>>>> main diff --git a/contrib/jemalloc/scripts/gen_travis.py b/contrib/jemalloc/scripts/gen_travis.py index c306744e6a65..4366a066eeab 100755 --- a/contrib/jemalloc/scripts/gen_travis.py +++ b/contrib/jemalloc/scripts/gen_travis.py @@ -1,4 +1,3 @@ -<<<<<<< HEAD #!/usr/bin/env python3 from itertools import combinations, chain @@ -326,155 +325,3 @@ def main(): if __name__ == '__main__': main() -||||||| dec341af7695 -======= -#!/usr/bin/env python - -from itertools import combinations - -travis_template = """\ -language: generic -dist: precise - -matrix: - include: -%s - -before_script: - - autoconf - - scripts/gen_travis.py > travis_script && diff .travis.yml travis_script - - ./configure ${COMPILER_FLAGS:+ \ - CC="$CC $COMPILER_FLAGS" \ - CXX="$CXX $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 --with-malloc-conf=tcache:false. 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 CXX=g++' -compilers_unusual = 'CC=clang CXX=clang++' - -compiler_flag_unusuals = ['-m32'] - -configure_flag_unusuals = [ - '--enable-debug', - '--enable-prof', - '--disable-stats', - '--disable-libdl', - '--enable-opt-safety-checks', -] - -malloc_conf_unusuals = [ - 'tcache:false', - 'dss:primary', - 'percpu_arena:percpu', - 'background_thread:true', -] - -all_unusuals = ( - [os_unusual] + [compilers_unusual] + compiler_flag_unusuals - + configure_flag_unusuals + malloc_conf_unusuals -) - -unusual_combinations_to_test = [] -for i in xrange(MAX_UNUSUAL_OPTIONS + 1): - unusual_combinations_to_test += combinations(all_unusuals, i) - -gcc_multilib_set = False -# Formats a job from a combination of flags -def format_job(combination): - global gcc_multilib_set - - os = os_unusual if os_unusual in combination else os_default - compilers = compilers_unusual if compilers_unusual in combination else compilers_default - - compiler_flags = [x for x in combination if x in compiler_flag_unusuals] - configure_flags = [x for x in combination if x in configure_flag_unusuals] - malloc_conf = [x for x in combination if x in malloc_conf_unusuals] - - # Filter out unsupported configurations on OS X. - if os == 'osx' and ('dss:primary' in malloc_conf or \ - 'percpu_arena:percpu' in malloc_conf or 'background_thread:true' \ - in malloc_conf): - return "" - if len(malloc_conf) > 0: - configure_flags.append('--with-malloc-conf=' + ",".join(malloc_conf)) - - # Filter out an unsupported configuration - heap profiling on OS X. - if os == 'osx' and '--enable-prof' in configure_flags: - return "" - - # We get some spurious errors when -Warray-bounds is enabled. - env_string = ('{} COMPILER_FLAGS="{}" CONFIGURE_FLAGS="{}" ' - 'EXTRA_CFLAGS="-Werror -Wno-array-bounds"').format( - compilers, " ".join(compiler_flags), " ".join(configure_flags)) - - job = "" - job += ' - os: %s\n' % os - job += ' env: %s\n' % env_string - if '-m32' in combination and os == 'linux': - job += ' addons:' - if gcc_multilib_set: - job += ' *gcc_multilib\n' - else: - job += ' &gcc_multilib\n' - job += ' apt:\n' - job += ' packages:\n' - job += ' - gcc-multilib\n' - gcc_multilib_set = True - return job - -include_rows = "" -for combination in unusual_combinations_to_test: - include_rows += format_job(combination) - -# Development build -include_rows += '''\ - # Development build - - os: linux - env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--enable-debug --disable-cache-oblivious --enable-stats --enable-log --enable-prof" EXTRA_CFLAGS="-Werror -Wno-array-bounds" -''' - -# Enable-expermental-smallocx -include_rows += '''\ - # --enable-expermental-smallocx: - - os: linux - env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--enable-debug --enable-experimental-smallocx --enable-stats --enable-prof" EXTRA_CFLAGS="-Werror -Wno-array-bounds" -''' - -# Valgrind build bots -include_rows += ''' - # Valgrind - - os: linux - env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="" EXTRA_CFLAGS="-Werror -Wno-array-bounds" JEMALLOC_TEST_PREFIX="valgrind" - addons: - apt: - packages: - - valgrind -''' - -# To enable valgrind on macosx add: -# -# - os: osx -# env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="" EXTRA_CFLAGS="-Werror -Wno-array-bounds" JEMALLOC_TEST_PREFIX="valgrind" -# install: brew install valgrind -# -# It currently fails due to: https://github.com/jemalloc/jemalloc/issues/1274 - -print travis_template % include_rows ->>>>>>> main diff --git a/contrib/jemalloc/src/jemalloc_cpp.cpp b/contrib/jemalloc/src/jemalloc_cpp.cpp index d606686e0c97..451655f1b5a5 100644 --- a/contrib/jemalloc/src/jemalloc_cpp.cpp +++ b/contrib/jemalloc/src/jemalloc_cpp.cpp @@ -1,4 +1,3 @@ -<<<<<<< HEAD #include <mutex> #include <new> @@ -253,147 +252,3 @@ operator delete[](void* ptr, std::size_t size, std::align_val_t alignment) noexc } #endif // __cpp_aligned_new -||||||| dec341af7695 -======= -#include <mutex> -#include <new> - -#define JEMALLOC_CPP_CPP_ -#ifdef __cplusplus -extern "C" { -#endif - -#include "jemalloc/internal/jemalloc_preamble.h" -#include "jemalloc/internal/jemalloc_internal_includes.h" - -#ifdef __cplusplus -} -#endif - -// All operators in this file are exported. - -// Possibly alias hidden versions of malloc and sdallocx to avoid an extra plt -// thunk? -// -// extern __typeof (sdallocx) sdallocx_int -// __attribute ((alias ("sdallocx"), -// visibility ("hidden"))); -// -// ... but it needs to work with jemalloc namespaces. - -void *operator new(std::size_t size); -void *operator new[](std::size_t size); -void *operator new(std::size_t size, const std::nothrow_t &) noexcept; -void *operator new[](std::size_t size, const std::nothrow_t &) noexcept; -void operator delete(void *ptr) noexcept; -void operator delete[](void *ptr) noexcept; -void operator delete(void *ptr, const std::nothrow_t &) noexcept; -void operator delete[](void *ptr, const std::nothrow_t &) noexcept; - -#if __cpp_sized_deallocation >= 201309 -/* C++14's sized-delete operators. */ -void operator delete(void *ptr, std::size_t size) noexcept; -void operator delete[](void *ptr, std::size_t size) noexcept; -#endif - -JEMALLOC_NOINLINE -static void * -handleOOM(std::size_t size, bool nothrow) { - void *ptr = nullptr; - - while (ptr == nullptr) { - std::new_handler handler; - // GCC-4.8 and clang 4.0 do not have std::get_new_handler. - { - static std::mutex mtx; - std::lock_guard<std::mutex> lock(mtx); - - handler = std::set_new_handler(nullptr); - std::set_new_handler(handler); - } - if (handler == nullptr) - break; - - try { - handler(); - } catch (const std::bad_alloc &) { - break; - } - - ptr = je_malloc(size); - } - - if (ptr == nullptr && !nothrow) - std::__throw_bad_alloc(); - return ptr; -} - -template <bool IsNoExcept> -JEMALLOC_ALWAYS_INLINE -void * -newImpl(std::size_t size) noexcept(IsNoExcept) { - void *ptr = je_malloc(size); - if (likely(ptr != nullptr)) - return ptr; - - return handleOOM(size, IsNoExcept); -} - -void * -operator new(std::size_t size) { - return newImpl<false>(size); -} - -void * -operator new[](std::size_t size) { - return newImpl<false>(size); -} - -void * -operator new(std::size_t size, const std::nothrow_t &) noexcept { - return newImpl<true>(size); -} - -void * -operator new[](std::size_t size, const std::nothrow_t &) noexcept { - return newImpl<true>(size); -} - -void -operator delete(void *ptr) noexcept { - je_free(ptr); -} - -void -operator delete[](void *ptr) noexcept { - je_free(ptr); -} - -void -operator delete(void *ptr, const std::nothrow_t &) noexcept { - je_free(ptr); -} - -void operator delete[](void *ptr, const std::nothrow_t &) noexcept { - je_free(ptr); -} - -#if __cpp_sized_deallocation >= 201309 - -void -operator delete(void *ptr, std::size_t size) noexcept { - if (unlikely(ptr == nullptr)) { - return; - } - je_sdallocx_noflags(ptr, size); -} - -void operator delete[](void *ptr, std::size_t size) noexcept { - if (unlikely(ptr == nullptr)) { - return; - } - je_sdallocx_noflags(ptr, size); -} - -#endif // __cpp_sized_deallocation ->>>>>>> main diff --git a/contrib/libucl/CMakeLists.txt b/contrib/libucl/CMakeLists.txt deleted file mode 100644 index 5fe772a30f88..000000000000 --- a/contrib/libucl/CMakeLists.txt +++ /dev/null @@ -1,314 +0,0 @@ -PROJECT(libucl C) -CMAKE_MINIMUM_REQUIRED(VERSION 2.6.0 FATAL_ERROR) - -SET(LIBUCL_VERSION_MAJOR 0) -SET(LIBUCL_VERSION_MINOR 5) -SET(LIBUCL_VERSION_PATCH 0) - -SET(LIBUCL_VERSION - "${LIBUCL_VERSION_MAJOR}.${LIBUCL_VERSION_MINOR}.${LIBUCL_VERSION_PATCH}") - -INCLUDE(CheckCCompilerFlag) -INCLUDE(CheckCSourceCompiles) -INCLUDE(FindOpenSSL) -INCLUDE(GNUInstallDirs) - -OPTION(ENABLE_URL_INCLUDE "Enable urls in ucl includes (requires libcurl or libfetch) [default: OFF]" OFF) -OPTION(ENABLE_URL_SIGN "Enable signatures check in ucl includes (requires openssl) [default: OFF]" OFF) -OPTION(BUILD_SHARED_LIBS "Build Shared Libraries [default: OFF]" OFF) -OPTION(ENABLE_LUA "Enable lua support [default: OFF]" OFF) -OPTION(ENABLE_LUAJIT "Enable luajit support [default: OFF]" OFF) -OPTION(ENABLE_UTILS "Enable building utility binaries [default: OFF]" OFF) - -# Find lua installation -MACRO(FindLua) - # Find lua libraries - UNSET(LUA_INCLUDE_DIR CACHE) - UNSET(LUA_LIBRARY CACHE) - CMAKE_PARSE_ARGUMENTS(LUA "" "VERSION_MAJOR;VERSION_MINOR;ROOT" "" ${ARGN}) - - IF(NOT LUA_VERSION_MAJOR OR NOT LUA_VERSION_MINOR) - MESSAGE(FATAL_ERROR "Invalid FindLua invocation: ${ARGN}") - ENDIF() - - IF(ENABLE_LUAJIT MATCHES "ON") - MESSAGE(STATUS "Check for luajit ${LUA_VERSION_MAJOR}.${LUA_VERSION_MINOR}") - FIND_PATH(LUA_INCLUDE_DIR luajit.h - HINTS - "${RSPAMD_SEARCH_PATH}" "${LUA_ROOT}" - $ENV{LUA_DIR} - PATH_SUFFIXES "include/luajit-2.0" - "include/luajit${LUA_VERSION_MAJOR}${LUA_VERSION_MINOR}" - "include/luajit${LUA_VERSION_MAJOR}.${LUA_VERSION_MINOR}" - "include/luajit-${LUA_VERSION_MAJOR}.${LUA_VERSION_MINOR}" - "include/luajit" - "include/lua${LUA_VERSION_MAJOR}${LUA_VERSION_MINOR}" - "include/lua${LUA_VERSION_MAJOR}.${LUA_VERSION_MINOR}" - "include/lua-${LUA_VERSION_MAJOR}.${LUA_VERSION_MINOR}" - include/lua include - PATHS ${RSPAMD_DEFAULT_INCLUDE_PATHS} - ) - FIND_LIBRARY(LUA_LIBRARY - NAMES luajit - "luajit-2.0" - "luajit2.0" - "luajit${LUA_VERSION_MAJOR}${LUA_VERSION_MINOR}" - "luajit${LUA_VERSION_MAJOR}.${LUA_VERSION_MINOR}" - "luajit-${LUA_VERSION_MAJOR}.${LUA_VERSION_MINOR}" - HINTS - "${RSPAMD_SEARCH_PATH}" "${LUA_ROOT}" - $ENV{LUA_DIR} - PATH_SUFFIXES lib64 lib - PATHS ${RSPAMD_DEFAULT_LIBRARY_PATHS} - DOC "Lua library" - ) - - IF(NOT LUA_LIBRARY OR NOT LUA_INCLUDE_DIR) - MESSAGE(STATUS "Fallback from luajit to plain lua") - SET(ENABLE_LUAJIT "OFF") - MESSAGE(STATUS "Check for lua ${LUA_VERSION_MAJOR}.${LUA_VERSION_MINOR}") - FIND_PATH(LUA_INCLUDE_DIR lua.h - HINTS - "${RSPAMD_SEARCH_PATH}" "${LUA_ROOT}" - $ENV{LUA_DIR} - PATH_SUFFIXES "include/lua${LUA_VERSION_MAJOR}${LUA_VERSION_MINOR}" - "include/lua${LUA_VERSION_MAJOR}.${LUA_VERSION_MINOR}" - "include/lua-${LUA_VERSION_MAJOR}.${LUA_VERSION_MINOR}" - include/lua include - PATHS ${RSPAMD_DEFAULT_INCLUDE_PATHS} - ) - FIND_LIBRARY(LUA_LIBRARY - NAMES lua - "lua${LUA_VERSION_MAJOR}${LUA_VERSION_MINOR}" - "lua${LUA_VERSION_MAJOR}.${LUA_VERSION_MINOR}" - "lua-${LUA_VERSION_MAJOR}.${LUA_VERSION_MINOR}" - HINTS - "${RSPAMD_SEARCH_PATH}" "${LUA_ROOT}" - $ENV{LUA_DIR} - PATH_SUFFIXES lib64 lib - PATHS ${RSPAMD_DEFAULT_LIBRARY_PATHS} - DOC "Lua library" - ) - ENDIF() - ELSE(ENABLE_LUAJIT MATCHES "ON") - MESSAGE(STATUS "Check for lua ${LUA_VERSION_MAJOR}.${LUA_VERSION_MINOR}") - FIND_PATH(LUA_INCLUDE_DIR lua.h - HINTS - "${RSPAMD_SEARCH_PATH}" "${LUA_ROOT}" - $ENV{LUA_DIR} - PATH_SUFFIXES "include/lua${LUA_VERSION_MAJOR}${LUA_VERSION_MINOR}" - "include/lua${LUA_VERSION_MAJOR}.${LUA_VERSION_MINOR}" - "include/lua-${LUA_VERSION_MAJOR}.${LUA_VERSION_MINOR}" - include/lua include - PATHS ${RSPAMD_DEFAULT_INCLUDE_PATHS} - ) - FIND_LIBRARY(LUA_LIBRARY - NAMES lua - "lua${LUA_VERSION_MAJOR}${LUA_VERSION_MINOR}" - "lua${LUA_VERSION_MAJOR}.${LUA_VERSION_MINOR}" - "lua-${LUA_VERSION_MAJOR}.${LUA_VERSION_MINOR}" - HINTS - "${RSPAMD_SEARCH_PATH}" "${LUA_ROOT}" - $ENV{LUA_DIR} - PATH_SUFFIXES lib64 lib - PATHS ${RSPAMD_DEFAULT_LIBRARY_PATHS} - DOC "Lua library" - ) - ENDIF(ENABLE_LUAJIT MATCHES "ON") - - IF(LUA_LIBRARY AND LUA_INCLUDE_DIR) - SET(LUA_FOUND 1) - IF(NOT LUA_VERSION_MAJOR OR NOT LUA_VERSION_MINOR) - SET(LUA_VERSION_MAJOR ${LUA_VERSION_MAJOR}) - SET(LUA_VERSION_MINOR ${LUA_VERSION_MINOR}) - ENDIF(NOT LUA_VERSION_MAJOR OR NOT LUA_VERSION_MINOR) - IF(ENABLE_LUAJIT MATCHES "ON") - MESSAGE(STATUS "Found luajit ${LUA_VERSION_MAJOR}.${LUA_VERSION_MINOR}") - ELSE(ENABLE_LUAJIT MATCHES "ON") - MESSAGE(STATUS "Found lua ${LUA_VERSION_MAJOR}.${LUA_VERSION_MINOR}") - ENDIF(ENABLE_LUAJIT MATCHES "ON") - ENDIF(LUA_LIBRARY AND LUA_INCLUDE_DIR) -ENDMACRO() - -IF(CMAKE_SYSTEM_NAME STREQUAL "Linux") - LIST(APPEND CMAKE_REQUIRED_LIBRARIES rt) -ENDIF(CMAKE_SYSTEM_NAME STREQUAL "Linux") - -IF(ENABLE_URL_INCLUDE MATCHES "ON") - FIND_LIBRARY(LIBFETCH_LIBRARY NAMES fetch PATHS PATH_SUFFIXES lib64 lib - PATHS - ~/Library/Frameworks - /Library/Frameworks - /usr/local - /usr - /sw - /opt/local - /opt/csw - /opt - DOC "Path where the libfetch library can be found") - IF(LIBFETCH_LIBRARY) - FIND_FILE(HAVE_FETCH_H NAMES fetch.h PATHS /usr/include - /opt/include - /usr/local/include - DOC "Path to libfetch header") - ELSE(LIBFETCH_LIBRARY) - # Try to find libcurl - FIND_PACKAGE(CURL) - IF(NOT CURL_FOUND) - MESSAGE(WARNING "Neither libcurl nor libfetch were found, no support of URL includes in configuration") - ENDIF(NOT CURL_FOUND) - ENDIF(LIBFETCH_LIBRARY) -ENDIF(ENABLE_URL_INCLUDE MATCHES "ON") - -set(SYNC_BUILTINS_TEST_SOURCE [====[ -int main() -{ - unsigned long val; - - __sync_bool_compare_and_swap(&val, 0, 1); - __sync_add_and_fetch(&val, 1); - __sync_fetch_and_add(&val, 0); - __sync_sub_and_fetch(&val, 1); - - return 0; -} -]====]) - -CHECK_C_SOURCE_COMPILES("${SYNC_BUILTINS_TEST_SOURCE}" HAVE_ATOMIC_BUILTINS) -IF(NOT HAVE_ATOMIC_BUILTINS) - MESSAGE(WARNING "Libucl references could be thread-unsafe because atomic builtins are missing") -ENDIF(NOT HAVE_ATOMIC_BUILTINS) - -SET(CMAKE_C_WARN_FLAGS "") -CHECK_C_COMPILER_FLAG(-W SUPPORT_W) -CHECK_C_COMPILER_FLAG(-Wno-pointer-sign SUPPORT_WPOINTER_SIGN) -CHECK_C_COMPILER_FLAG(-Wno-unused-parameter SUPPORT_WUNUSED_PARAMETER) -IF(SUPPORT_W) - SET(CMAKE_C_WARN_FLAGS "${CMAKE_C_WARN_FLAGS} -W") -ENDIF(SUPPORT_W) -IF(SUPPORT_WPOINTER_SIGN) - SET(CMAKE_C_WARN_FLAGS "${CMAKE_C_WARN_FLAGS} -Wno-pointer-sign") -ENDIF(SUPPORT_WPOINTER_SIGN) -IF(SUPPORT_WUNUSED_PARAMETER) - SET(CMAKE_C_WARN_FLAGS "${CMAKE_C_WARN_FLAGS} -Wno-unused-parameter") -ENDIF(SUPPORT_WUNUSED_PARAMETER) - -SET( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${CMAKE_C_WARN_FLAGS}" ) - -IF(ENABLE_URL_SIGN MATCHES "ON") - IF(OPENSSL_FOUND) - SET(HAVE_OPENSSL 1) - INCLUDE_DIRECTORIES("${OPENSSL_INCLUDE_DIR}") - ENDIF(OPENSSL_FOUND) -ENDIF(ENABLE_URL_SIGN MATCHES "ON") - -SET(UCL_COMPILE_DEFS) -IF(HAVE_FETCH_H) - LIST(APPEND UCL_COMPILE_DEFS -DHAVE_FETCH_H=1) -ENDIF(HAVE_FETCH_H) -IF(CURL_FOUND) - LIST(APPEND UCL_COMPILE_DEFS -DCURL_FOUND=1) -ENDIF(CURL_FOUND) -IF(HAVE_OPENSSL) - LIST(APPEND UCL_COMPILE_DEFS -DHAVE_OPENSSL=1) -ENDIF(HAVE_OPENSSL) -IF(HAVE_ATOMIC_BUILTINS) - LIST(APPEND UCL_COMPILE_DEFS -DHAVE_ATOMIC_BUILTINS=1) -ENDIF(HAVE_ATOMIC_BUILTINS) - -SET(UCLSRC src/ucl_util.c - src/ucl_parser.c - src/ucl_emitter.c - src/ucl_emitter_streamline.c - src/ucl_emitter_utils.c - src/ucl_hash.c - src/ucl_schema.c - src/ucl_msgpack.c - src/ucl_sexp.c) - -SET(UCLHDR include/ucl.h - include/ucl++.h) - -SET (LIB_TYPE STATIC) -IF (BUILD_SHARED_LIBS) - SET (LIB_TYPE SHARED) -ENDIF (BUILD_SHARED_LIBS) -ADD_LIBRARY(ucl ${LIB_TYPE} ${UCLSRC}) -ADD_LIBRARY(ucl::ucl ALIAS ucl) -SET_TARGET_PROPERTIES(ucl PROPERTIES VERSION ${LIBUCL_VERSION} SOVERSION ${LIBUCL_VERSION_MAJOR}) -TARGET_INCLUDE_DIRECTORIES(ucl - PUBLIC - include - PRIVATE - src - uthash - klib) -TARGET_COMPILE_DEFINITIONS(ucl - PRIVATE - ${UCL_COMPILE_DEFS} -) - -IF(ENABLE_LUA MATCHES "ON") - IF(ENABLE_LUAJIT MATCHES "ON") - FindLua(VERSION_MAJOR "5" VERSION_MINOR "1" ROOT "${LUA_ROOT}") - IF(NOT LUA_FOUND) - MESSAGE(FATAL_ERROR "Lua not found, lua support is required") - ELSE(NOT LUA_FOUND) - INCLUDE_DIRECTORIES("${LUA_INCLUDE_DIR}") - ENDIF(NOT LUA_FOUND) - ELSE(ENABLE_LUAJIT MATCHES "ON") - FindLua(VERSION_MAJOR "5" VERSION_MINOR "2" ROOT "${LUA_ROOT}") - IF(NOT LUA_FOUND) - FindLua(VERSION_MAJOR "5" VERSION_MINOR "1" ROOT "${LUA_ROOT}") - ENDIF(NOT LUA_FOUND) - IF(NOT LUA_FOUND) - MESSAGE(FATAL_ERROR "Lua not found, lua support is required") - ELSE(NOT LUA_FOUND) - INCLUDE_DIRECTORIES("${LUA_INCLUDE_DIR}") - ENDIF(NOT LUA_FOUND) - ENDIF(ENABLE_LUAJIT MATCHES "ON") - SET(UCL_LUA_SRC lua/lua_ucl.c) - ADD_LIBRARY(lua-ucl ${LIB_TYPE} ${UCL_LUA_SRC}) - ADD_LIBRARY(ucl::lua ALIAS lua-ucl) - IF(ENABLE_LUAJIT MATCHES "ON") - TARGET_LINK_LIBRARIES(lua-ucl "${LUAJIT_LIBRARY}") - ELSE(ENABLE_LUAJIT MATCHES "ON") - TARGET_LINK_LIBRARIES(lua-ucl "${LUA_LIBRARY}") - ENDIF(ENABLE_LUAJIT MATCHES "ON") - TARGET_LINK_LIBRARIES(lua-ucl ucl) - TARGET_INCLUDE_DIRECTORIES(lua-ucl PUBLIC include PRIVATE src uthash) - SET_TARGET_PROPERTIES(lua-ucl PROPERTIES - VERSION ${LIBUCL_VERSION} - SOVERSION ${LIBUCL_VERSION_MAJOR} - PUBLIC_HEADER include/lua_ucl.h) - INSTALL(TARGETS lua-ucl DESTINATION ${CMAKE_INSTALL_LIBDIR} - PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) -ENDIF() - -IF(HAVE_FETCH_H) - TARGET_LINK_LIBRARIES(ucl fetch) -ELSE(HAVE_FETCH_H) - IF(CURL_FOUND) - TARGET_LINK_LIBRARIES(ucl ${CURL_LIBRARIES}) - ENDIF(CURL_FOUND) -ENDIF(HAVE_FETCH_H) -IF(ENABLE_URL_SIGN MATCHES "ON") - IF(OPENSSL_FOUND) - TARGET_LINK_LIBRARIES(ucl ${OPENSSL_LIBRARIES}) - ENDIF(OPENSSL_FOUND) -ENDIF(ENABLE_URL_SIGN MATCHES "ON") - -IF(UNIX) - TARGET_LINK_LIBRARIES(ucl -lm) -ENDIF(UNIX) - -SET_TARGET_PROPERTIES(ucl PROPERTIES - PUBLIC_HEADER "${UCLHDR}") - -INSTALL(TARGETS ucl DESTINATION ${CMAKE_INSTALL_LIBDIR} - PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) - -IF(ENABLE_UTILS MATCHES "ON") - ADD_SUBDIRECTORY(utils) -ENDIF() - diff --git a/contrib/libucl/ChangeLog.md b/contrib/libucl/ChangeLog.md deleted file mode 100644 index cba29aa9a7b5..000000000000 --- a/contrib/libucl/ChangeLog.md +++ /dev/null @@ -1,103 +0,0 @@ -# Version history - -## Libucl 0.5 - -- Streamline emitter has been added, so it is now possible to output partial `ucl` objects -- Emitter now is more flexible due to emitter_context structure - -### 0.5.1 -- Fixed number of bugs and memory leaks - -### 0.5.2 - -- Allow userdata objects to be emitted and destructed -- Use userdata objects to store lua function references - -### Libucl 0.6 - -- Reworked macro interface - -### Libucl 0.6.1 - -- Various utilities fixes - -### Libucl 0.7.0 - -- Move to klib library from uthash to reduce memory overhead and increase performance - -### Libucl 0.7.1 - -- Added safe iterators API - -### Libucl 0.7.2 - -- Fixed serious bugs in schema and arrays iteration - -### Libucl 0.7.3 - -- Fixed a bug with macros that come after an empty object -- Fixed a bug in include processing when an incorrect variable has been destroyed (use-after-free) - -### Libucl 0.8.0 - -- Allow to save comments and macros when parsing UCL documents -- C++ API -- Python bindings (by Eitan Adler) -- Add msgpack support for parser and emitter -- Add Canonical S-expressions parser for libucl -- CLI interface for parsing and validation (by Maxim Ignatenko) -- Implement include with priority -- Add 'nested' functionality to .include macro (by Allan Jude) -- Allow searching an array of paths for includes (by Allan Jude) -- Add new .load macro (by Allan Jude) -- Implement .inherit macro (#100) -- Add merge strategies -- Add schema validation to lua API -- Add support for external references to schema validation -- Add coveralls integration to libucl -- Implement tests for 80% of libucl code lines -- Fix tonns of minor and major bugs -- Improve documentation -- Rework function names to the common conventions (old names are preserved for backwards compatibility) -- Add Coverity scan integration -- Add fuzz tests - -**Incompatible changes**: - -- `ucl_object_emit_full` now accepts additional argument `comments` that could be used to emit comments with UCL output - -### Libucl 0.8.1 - -- Create ucl_parser_add_file_full() to be able to specify merge mode and parser type (by Allan Jude) -- C++ wrapper improvements (by @ftilde) -- C++ wrapper: add convenience method at() and lookup() (by Yonghee Kim) -- C++ wrapper: add assignment operator to Ucl class (by Yonghee Kim) -- C++ wrapper: support variables in parser (by Yonghee Kim) -- C++ wrapper: refactoring C++ interface (by Yonghee Kim): - - use auto variables (if possible) - - remove dangling expressions - - use std::set::emplace instead of std::set::insert - - not use std::move in return statement; considering copy elision -- C++ wrapper: fix compilation error and warnings (by Zhe Wang) -- C++ wrapper: fix iteration over objects in which the first value is `false` (by Zhe Wang) -- C++ wrapper: Macro helper functions (by Chris Meacham) -- C++ wrapper: Changing the duplicate strategy in the C++ API (by Chris Meacham) -- C++ wrapper: Added access functions for the size of a UCL_ARRAY (by Chris Meacham) -- Fix caseless comparison -- Fix include when EPERM is issued -- Fix Windows build -- Allow to reserve space in arrays and hashes -- Fix bug with including of empty files -- Move to mum_hash from xxhash -- Fix msgpack on non-x86 -- python: Add support to Python 3 (by Denis Volpato Martins) -- python: Add support for Python 2.6 tests (by Denis Volpato Martins) -- python: Implement validation function and tests (by Denis Volpato Martins) -- python: Added UCL_NULL handling and tests (by Denis Volpato Martins) -- Fix schema validation for patternProperties with object data (by Denis Volpato Martins) -- Remove the dependency on NBBY, add missing <strings.h> include (by Ed Schouten) -- Allow to emit msgpack from Lua -- Performance improvements in Lua API -- Allow to pass opaque objects in Lua API for transparent C passthrough -- Various bugs fixed -- Couple of memory leaks plugged
\ No newline at end of file diff --git a/contrib/libucl/FREEBSD-Xlist b/contrib/libucl/FREEBSD-Xlist new file mode 100644 index 000000000000..6d8cb4ff8f5b --- /dev/null +++ b/contrib/libucl/FREEBSD-Xlist @@ -0,0 +1,40 @@ +.github +.gitignore +CMakeLists.txt +ChangeLog.md +Makefile.am +Makefile.unix +Makefile.w32 +README.md +autogen.sh +configure.ac +doc/Makefile.am +doc/api.md +doc/lua_api.md +doc/pandoc.template +examples/ucl_cpp.cc +haskell/hucl.hs +libucl.pc.in +lua/Makefile.am +lua/libucl.rockspec.in +m4/.gitignore +m4/ax_lua.m4 +m4/gcov.m4 +python/MANIFEST.in +python/setup.py +python/src/uclmodule.c +python/tests/__init__.py +python/tests/compat.py +python/tests/test_dump.py +python/tests/test_example.py +python/tests/test_load.py +python/tests/test_validation.py +python/ucl.pyi +src/Makefile.am +stamp-h.in +tests/Makefile.am +utils/CMakeLists.txt +utils/Makefile.am +utils/chargen.c +utils/objdump.c +utils/ucl-tool.c diff --git a/contrib/libucl/FREEBSD-upgrade b/contrib/libucl/FREEBSD-upgrade new file mode 100644 index 000000000000..b80736d7877b --- /dev/null +++ b/contrib/libucl/FREEBSD-upgrade @@ -0,0 +1,39 @@ +# FreeBSD libucl import instruction +# +# At least the following ports are required when importing libucl: +# - devel/autoconf +# - devel/automake +# - devel/git +# - devel/gmake +# - devel/libtool +# +# 1. Vendor import +# +# $ git clone https://github.com/vstakhov/libucl.git /tmp/libucl +# $ cd /tmp/libucl +# $ git checkout <REF_BRANCH_TO_BE_IMPORTED> +# $ cd /usr/src +# $ git checkout vendor/libucl +# $ rsync -va --delete --exclude=.git /tmp/libucl/ /usr/src/contrib/libucl/ +# $ git add . +# $ git commit -m "vendor import libucl <REF_BRANCH_TO_BE_IMPORTED>" +# $ git tag -a vendor/libucl/<REF_BRANCH_TO_BE_IMPORTED> -m "vendor import libucl <REF_BRANCH_TO_BE_IMPORTED>" +# $ git push --follow-tags freebsd vendor/libucl/<REF_BRANCH_TO_BE_IMPORTED> +# +# 2. Test +# +# $ cd /usr/src +# $ git checkout vendor/libucl/<REF_BRANCH_TO_BE_IMPORTED> +# $ ./autogen.sh +# $ ./configure +# $ gmake +# $ gmake check +# $ gmake clean +# +# 3. Merge vendor tree +# +# $ git subtree merge -P contrib/libucl vendor/libucl/<REF_BRANCH_TO_BE_IMPORTED> +# $ sh -c 'for F in `cat FREEBSD-Xlist | grep -v FreeBSD`; do rm -rf ./$F ; done' +# +# Recheck if there were any new files were added which are not necessary in the +# contrib tree. If so, remove them and also add them to the FREEBSD-Xlist file. diff --git a/contrib/libucl/Makefile.am b/contrib/libucl/Makefile.am deleted file mode 100644 index 5b51bcc3b468..000000000000 --- a/contrib/libucl/Makefile.am +++ /dev/null @@ -1,81 +0,0 @@ -ACLOCAL_AMFLAGS = -I m4 -EXTRA_DIST = uthash klib README.md - -pkgconfigdir = $(libdir)/pkgconfig -pkgconfig_DATA = libucl.pc - -if LUA_SUB - LUA_SUBDIR = lua -endif - -COVERAGE_INFO_FILE = $(top_builddir)/coverage.info -COVERAGE_REPORT_DIR = $(top_builddir)/coverage - -.PHONY = coverage-requirement-check clean-coverage-report - -coverage-requirement-check: - @if test ! -e $(GCOV); then \ - echo "Cannot find $(GCOV). Please install gcov."; \ - exit 1; \ - fi - -coverage: coverage-requirement-check clean-coverage coverage-build coverage-check coverage-report - @echo "Please execute 'make clean' before 'make' or 'make check' to remove instrumented object files(compiled with -O0 etc.). Note that 'make clean' also remove coverage data." - -coverage-build: coverage-requirement-check - @if test `find $(top_builddir) -name "*.gcno" | wc -l` -eq 0; then \ - echo "Start to remove old non-instrumented object files..."; \ - $(MAKE) $(AM_MAKEFLAGS) clean; \ - echo "Successfully removed old non-instrumented object files."; \ - fi - @echo "Start to build libraries with coverage options..." - $(MAKE) $(AM_MAKEFLAGS) \ - CFLAGS="$(CFLAGS) $(COVERAGE_CFLAGS) $(COVERAGE_OPTFLAGS)" \ - CXXFLAGS="$(CXXFLAGS) $(COVERAGE_CXXFLAGS) $(COVERAGE_OPTFLAGS)" \ - LDFLAGS="$(LDFLAGS) $(COVERAGE_LDFLAGS)" \ - LIBS="$(LIBS) $(COVERAGE_LIBS)" - @echo "Successfully built libraries with coverage options." - -coverage-check: coverage-requirement-check - @echo "Start to run tests with instrumented libraries..." - $(MAKE) $(AM_MAKEFLAGS) check \ - CFLAGS="$(CFLAGS) $(COVERAGE_CFLAGS) $(COVERAGE_OPTFLAGS)" \ - CXXFLAGS="$(CXXFLAGS) $(COVERAGE_CXXFLAGS) $(COVERAGE_OPTFLAGS)" \ - LDFLAGS="$(LDFLAGS) $(COVERAGE_LDFLAGS)" \ - LIBS="$(LIBS) $(COVERAGE_LIBS)" - @echo "Successfully run tests with instrumented libraries." - -coverage-lcov: coverage-check coverage-requirement-check - $(LCOV) --capture \ - --directory "$(top_builddir)/" \ - --output-file $(COVERAGE_INFO_FILE) \ - --gcov-tool $(GCOV) \ - --compat-libtool --checksum - $(LCOV) --extract $(COVERAGE_INFO_FILE) `pwd`/src/ucl_\* \ - --output-file $(COVERAGE_INFO_FILE) - -coverage-report: coverage-lcov - @echo "Start to create coverage reports..." - $(GENHTML) --prefix "$(top_srcdir)" \ - --output-directory $(COVERAGE_REPORT_DIR) \ - --title $(PACKAGE_NAME) \ - --legend --show-details \ - $(GENHTML_OPTIONS) \ - $(COVERAGE_INFO_FILE) - @echo "Successfully created coverage reports into $(COVERAGE_REPORT_DIR) directory." - -clean-coverage-report: - -rm -rf $(COVERAGE_INFO_FILE) - -rm -rf $(COVERAGE_REPORT_DIR) - -clean-coverage: clean-coverage-report - -$(LCOV) --gcov-tool $(GCOV) --zerocounters --directory $(top_builddir) - @if xargs --version 2>/dev/null; then \ - find $(top_builddir) -name "*.gcno" | xargs --no-run-if-empty rm; \ - else \ - find $(top_builddir) -name "*.gcno" | xargs rm; \ - fi - -clean-local: clean-coverage - -SUBDIRS = src tests utils doc $(LUA_SUBDIR) diff --git a/contrib/libucl/Makefile.unix b/contrib/libucl/Makefile.unix deleted file mode 100644 index 0653d4843f7e..000000000000 --- a/contrib/libucl/Makefile.unix +++ /dev/null @@ -1,89 +0,0 @@ -CC ?= gcc -DESTDIR ?= /usr/local -LD ?= gcc -C_COMMON_FLAGS ?= -fPIC -Wall -W -Wno-unused-parameter -Wno-pointer-sign -I./include -I./uthash -I./src -I./klib -MAJOR_VERSION = 0 -MINOR_VERSION = 2 -PATCH_VERSION = 9 -VERSION = "$(MAJOR_VERSION).$(MINOR_VERSION).$(PATCH_VERSION)" -SONAME = libucl.so -SONAME_FULL = $(SONAME).$(MAJOR_VERSION) -OBJDIR ?= .obj -TESTDIR ?= tests -SRCDIR ?= src -INCLUDEDIR ?= include -MKDIR ?= mkdir -INSTALL ?= install -RM ?= rm -RMDIR ?= rmdir -LN ?= ln -LD_SHARED_FLAGS ?= -Wl,-soname,$(SONAME) -shared -lm -LD_UCL_FLAGS ?= -L$(OBJDIR) -Wl,-rpath,$(OBJDIR) -lucl -LD_ADD ?= -lrt -COPT_FLAGS ?= -O2 -HDEPS = $(SRCDIR)/ucl_hash.h \ - $(SRCDIR)/ucl_chartable.h \ - $(SRCDIR)/ucl_internal.h \ - $(INCLUDEDIR)/ucl.h \ - $(SRCDIR)/mum.h -OBJECTS = $(OBJDIR)/ucl_hash.o \ - $(OBJDIR)/ucl_util.o \ - $(OBJDIR)/ucl_parser.o \ - $(OBJDIR)/ucl_emitter.o \ - $(OBJDIR)/ucl_schema.o - -all: $(OBJDIR) $(OBJDIR)/$(SONAME) - -$(OBJDIR)/$(SONAME): $(OBJDIR)/$(SONAME_FULL) - $(LN) -sf $(SONAME_FULL) $(OBJDIR)/$(SONAME) - -$(OBJDIR)/$(SONAME_FULL): $(OBJECTS) - $(CC) -o $(OBJDIR)/$(SONAME_FULL) $(OBJECTS) $(LD_SHARED_FLAGS) $(LDFLAGS) $(SSL_LIBS) $(FETCH_LIBS) - -$(OBJDIR): - @$(MKDIR) -p $(OBJDIR) - -# Compile rules -$(OBJDIR)/ucl_util.o: $(SRCDIR)/ucl_util.c $(HDEPS) - $(CC) -o $(OBJDIR)/ucl_util.o $(CPPFLAGS) $(COPT_FLAGS) $(CFLAGS) $(C_COMMON_FLAGS) $(SSL_CFLAGS) $(FETCH_FLAGS) -c $(SRCDIR)/ucl_util.c -$(OBJDIR)/ucl_parser.o: $(SRCDIR)/ucl_parser.c $(HDEPS) - $(CC) -o $(OBJDIR)/ucl_parser.o $(CPPFLAGS) $(COPT_FLAGS) $(CFLAGS) $(C_COMMON_FLAGS) $(SSL_CFLAGS) $(FETCH_FLAGS) -c $(SRCDIR)/ucl_parser.c -$(OBJDIR)/ucl_emitter.o: $(SRCDIR)/ucl_emitter.c $(HDEPS) - $(CC) -o $(OBJDIR)/ucl_emitter.o $(CPPFLAGS) $(COPT_FLAGS) $(CFLAGS) $(C_COMMON_FLAGS) $(SSL_CFLAGS) $(FETCH_FLAGS) -c $(SRCDIR)/ucl_emitter.c -$(OBJDIR)/ucl_hash.o: $(SRCDIR)/ucl_hash.c $(HDEPS) - $(CC) -o $(OBJDIR)/ucl_hash.o $(CPPFLAGS) $(COPT_FLAGS) $(CFLAGS) $(C_COMMON_FLAGS) $(SSL_CFLAGS) $(FETCH_FLAGS) -c $(SRCDIR)/ucl_hash.c -$(OBJDIR)/ucl_schema.o: $(SRCDIR)/ucl_schema.c $(HDEPS) - $(CC) -o $(OBJDIR)/ucl_schema.o $(CPPFLAGS) $(COPT_FLAGS) $(CFLAGS) $(C_COMMON_FLAGS) $(SSL_CFLAGS) $(FETCH_FLAGS) -c $(SRCDIR)/ucl_schema.c - -clean: - $(RM) $(OBJDIR)/*.o $(OBJDIR)/$(SONAME_FULL) $(OBJDIR)/$(SONAME) $(OBJDIR)/chargen $(OBJDIR)/test_basic $(OBJDIR)/test_speed $(OBJDIR)/objdump $(OBJDIR)/test_generate $(OBJDIR)/test_schema || true - $(RMDIR) $(OBJDIR) - -# Utils - -chargen: utils/chargen.c $(OBJDIR)/$(SONAME) - $(CC) -o $(OBJDIR)/chargen $(CPPFLAGS) $(COPT_FLAGS) $(CFLAGS) $(C_COMMON_FLAGS) $(SSL_CFLAGS) $(FETCH_FLAGS) $(LDFLAGS) utils/chargen.c -objdump: utils/objdump.c $(OBJDIR)/$(SONAME) - $(CC) -o $(OBJDIR)/objdump $(CPPFLAGS) $(COPT_FLAGS) $(CFLAGS) $(C_COMMON_FLAGS) $(SSL_CFLAGS) $(FETCH_FLAGS) $(LDFLAGS) utils/objdump.c $(LD_UCL_FLAGS) - -# Tests - -test: $(OBJDIR) $(OBJDIR)/$(SONAME) $(OBJDIR)/test_basic $(OBJDIR)/test_speed $(OBJDIR)/test_generate $(OBJDIR)/test_schema - -run-test: test - TEST_DIR=$(TESTDIR) $(TESTDIR)/run_tests.sh $(OBJDIR)/test_basic $(OBJDIR)/test_speed $(OBJDIR)/test_generate $(OBJDIR)/test_schema - -$(OBJDIR)/test_basic: $(TESTDIR)/test_basic.c $(OBJDIR)/$(SONAME) - $(CC) -o $(OBJDIR)/test_basic $(CPPFLAGS) $(COPT_FLAGS) $(CFLAGS) $(C_COMMON_FLAGS) $(SSL_CFLAGS) $(FETCH_FLAGS) $(LDFLAGS) $(TESTDIR)/test_basic.c $(LD_UCL_FLAGS) -$(OBJDIR)/test_schema: $(TESTDIR)/test_schema.c $(OBJDIR)/$(SONAME) - $(CC) -o $(OBJDIR)/test_schema $(CPPFLAGS) $(COPT_FLAGS) $(CFLAGS) $(C_COMMON_FLAGS) $(SSL_CFLAGS) $(FETCH_FLAGS) $(LDFLAGS) $(TESTDIR)/test_schema.c $(LD_UCL_FLAGS) -$(OBJDIR)/test_speed: $(TESTDIR)/test_speed.c $(OBJDIR)/$(SONAME) - $(CC) -o $(OBJDIR)/test_speed $(CPPFLAGS) $(COPT_FLAGS) $(CFLAGS) $(C_COMMON_FLAGS) $(SSL_CFLAGS) $(FETCH_FLAGS) $(LDFLAGS) $(TESTDIR)/test_speed.c $(LD_UCL_FLAGS) $(LD_ADD) -$(OBJDIR)/test_generate: $(TESTDIR)/test_generate.c $(OBJDIR)/$(SONAME) - $(CC) -o $(OBJDIR)/test_generate $(CPPFLAGS) $(COPT_FLAGS) $(CFLAGS) $(C_COMMON_FLAGS) $(SSL_CFLAGS) $(FETCH_FLAGS) $(LDFLAGS) $(TESTDIR)/test_generate.c $(LD_UCL_FLAGS) $(LD_ADD) - -install: $(OBJDIR)/$(SONAME) - $(INSTALL) -m0755 $(SONAME) $(DESTDIR)/lib/$(SONAME) - $(INSTALL) -m0644 include/ucl.h $(DESTDIR)/include/ucl.h - -.PHONY: clean $(OBJDIR) diff --git a/contrib/libucl/Makefile.w32 b/contrib/libucl/Makefile.w32 deleted file mode 100644 index 5d9398bf1988..000000000000 --- a/contrib/libucl/Makefile.w32 +++ /dev/null @@ -1,92 +0,0 @@ -CC ?= gcc -DESTDIR ?= /usr/local -LD ?= gcc -C_COMMON_FLAGS ?= -fPIC -Wall -W -Wno-unused-parameter -Wno-pointer-sign -I./include -I./uthash -I./src -MAJOR_VERSION = 0 -MINOR_VERSION = 2 -PATCH_VERSION = 9 -VERSION = "$(MAJOR_VERSION).$(MINOR_VERSION).$(PATCH_VERSION)" -SONAME = libucl.dll -OBJDIR ?= .obj -TESTDIR ?= tests -SRCDIR ?= src -INCLUDEDIR ?= include -MKDIR ?= mkdir -INSTALL ?= install -RM ?= rm -RMDIR ?= rmdir -ifeq (Windows_NT, $(OS)) -LN ?= ln -else -LN ?= rem ln -endif -LD_SHARED_FLAGS ?= -Wl,-soname,$(SONAME) -shared -lm -LD_UCL_FLAGS ?= -L$(OBJDIR) -Wl,-rpath,$(OBJDIR) -lucl -LD_ADD ?= -lrt -COPT_FLAGS ?= -O2 -HDEPS = $(SRCDIR)/ucl_hash.h \ - $(SRCDIR)/ucl_chartable.h \ - $(SRCDIR)/ucl_internal.h \ - $(INCLUDEDIR)/ucl.h \ - $(SRCDIR)/mum.h -OBJECTS = $(OBJDIR)/ucl_hash.o \ - $(OBJDIR)/ucl_util.o \ - $(OBJDIR)/ucl_parser.o \ - $(OBJDIR)/ucl_emitter.o \ - $(OBJDIR)/ucl_emitter_utils.o \ - $(OBJDIR)/ucl_schema.o - -all: $(OBJDIR) $(OBJDIR)/$(SONAME) - -$(OBJDIR)/$(SONAME): $(OBJECTS) - $(CC) -o $(OBJDIR)/$(SONAME) $(OBJECTS) $(LD_SHARED_FLAGS) $(LDFLAGS) $(SSL_LIBS) $(FETCH_LIBS) - -$(OBJDIR): - @$(MKDIR) -p $(OBJDIR) - -# Compile rules -$(OBJDIR)/ucl_util.o: $(SRCDIR)/ucl_util.c $(HDEPS) - $(CC) -o $(OBJDIR)/ucl_util.o $(CPPFLAGS) $(COPT_FLAGS) $(CFLAGS) $(C_COMMON_FLAGS) $(SSL_CFLAGS) $(FETCH_FLAGS) -c $(SRCDIR)/ucl_util.c -$(OBJDIR)/ucl_parser.o: $(SRCDIR)/ucl_parser.c $(HDEPS) - $(CC) -o $(OBJDIR)/ucl_parser.o $(CPPFLAGS) $(COPT_FLAGS) $(CFLAGS) $(C_COMMON_FLAGS) $(SSL_CFLAGS) $(FETCH_FLAGS) -c $(SRCDIR)/ucl_parser.c -$(OBJDIR)/ucl_emitter.o: $(SRCDIR)/ucl_emitter.c $(HDEPS) - $(CC) -o $(OBJDIR)/ucl_emitter.o $(CPPFLAGS) $(COPT_FLAGS) $(CFLAGS) $(C_COMMON_FLAGS) $(SSL_CFLAGS) $(FETCH_FLAGS) -c $(SRCDIR)/ucl_emitter.c -$(OBJDIR)/ucl_emitter_utils.o: $(SRCDIR)/ucl_emitter_utils.c $(HDEPS) - $(CC) -o $(OBJDIR)/ucl_emitter_utils.o $(CPPFLAGS) $(COPT_FLAGS) $(CFLAGS) $(C_COMMON_FLAGS) $(SSL_CFLAGS) $(FETCH_FLAGS) -c $(SRCDIR)/ucl_emitter_utils.c -$(OBJDIR)/ucl_hash.o: $(SRCDIR)/ucl_hash.c $(HDEPS) - $(CC) -o $(OBJDIR)/ucl_hash.o $(CPPFLAGS) $(COPT_FLAGS) $(CFLAGS) $(C_COMMON_FLAGS) $(SSL_CFLAGS) $(FETCH_FLAGS) -c $(SRCDIR)/ucl_hash.c -$(OBJDIR)/ucl_schema.o: $(SRCDIR)/ucl_schema.c $(HDEPS) - $(CC) -o $(OBJDIR)/ucl_schema.o $(CPPFLAGS) $(COPT_FLAGS) $(CFLAGS) $(C_COMMON_FLAGS) $(SSL_CFLAGS) $(FETCH_FLAGS) -c $(SRCDIR)/ucl_schema.c -$(OBJDIR)/xxhash.o: $(SRCDIR)/xxhash.c $(HDEPS) - $(CC) -o $(OBJDIR)/xxhash.o $(CPPFLAGS) $(COPT_FLAGS) $(CFLAGS) $(C_COMMON_FLAGS) $(SSL_CFLAGS) $(FETCH_FLAGS) -c $(SRCDIR)/xxhash.c - -clean: - $(RM) $(OBJDIR)/*.o $(OBJDIR)/$(SONAME) $(OBJDIR)/$(SONAME) $(OBJDIR)/chargen $(OBJDIR)/test_basic $(OBJDIR)/test_speed $(OBJDIR)/objdump $(OBJDIR)/test_generate - $(RMDIR) $(OBJDIR) - -# Utils - -chargen: utils/chargen.c $(OBJDIR)/$(SONAME) - $(CC) -o $(OBJDIR)/chargen $(CPPFLAGS) $(COPT_FLAGS) $(CFLAGS) $(C_COMMON_FLAGS) $(SSL_CFLAGS) $(FETCH_FLAGS) $(LDFLAGS) utils/chargen.c -objdump: utils/objdump.c $(OBJDIR)/$(SONAME) - $(CC) -o $(OBJDIR)/objdump $(CPPFLAGS) $(COPT_FLAGS) $(CFLAGS) $(C_COMMON_FLAGS) $(SSL_CFLAGS) $(FETCH_FLAGS) $(LDFLAGS) utils/objdump.c $(LD_UCL_FLAGS) - -# Tests - -test: $(OBJDIR) $(OBJDIR)/$(SONAME) $(OBJDIR)/test_basic $(OBJDIR)/test_speed $(OBJDIR)/test_generate - -run-test: test - TEST_DIR=$(TESTDIR) $(TESTDIR)/run_tests.sh $(OBJDIR)/test_basic $(OBJDIR)/test_speed $(OBJDIR)/test_generate - -$(OBJDIR)/test_basic: $(TESTDIR)/test_basic.c $(OBJDIR)/$(SONAME) - $(CC) -o $(OBJDIR)/test_basic $(CPPFLAGS) $(COPT_FLAGS) $(CFLAGS) $(C_COMMON_FLAGS) $(SSL_CFLAGS) $(FETCH_FLAGS) $(LDFLAGS) $(TESTDIR)/test_basic.c $(LD_UCL_FLAGS) -$(OBJDIR)/test_speed: $(TESTDIR)/test_speed.c $(OBJDIR)/$(SONAME) - $(CC) -o $(OBJDIR)/test_speed $(CPPFLAGS) $(COPT_FLAGS) $(CFLAGS) $(C_COMMON_FLAGS) $(SSL_CFLAGS) $(FETCH_FLAGS) $(LDFLAGS) $(TESTDIR)/test_speed.c $(LD_UCL_FLAGS) $(LD_ADD) -$(OBJDIR)/test_generate: $(TESTDIR)/test_generate.c $(OBJDIR)/$(SONAME) - $(CC) -o $(OBJDIR)/test_generate $(CPPFLAGS) $(COPT_FLAGS) $(CFLAGS) $(C_COMMON_FLAGS) $(SSL_CFLAGS) $(FETCH_FLAGS) $(LDFLAGS) $(TESTDIR)/test_generate.c $(LD_UCL_FLAGS) $(LD_ADD) - -install: $(OBJDIR)/$(SONAME) - $(INSTALL) -m0755 $(SONAME) $(DESTDIR)/lib/$(SONAME) - $(INSTALL) -m0644 include/ucl.h $(DESTDIR)/include/ucl.h - -.PHONY: clean $(OBJDIR) diff --git a/contrib/libucl/README.md b/contrib/libucl/README.md deleted file mode 100644 index 53d8a651d73b..000000000000 --- a/contrib/libucl/README.md +++ /dev/null @@ -1,418 +0,0 @@ -# LIBUCL - -[](https://circleci.com/gh/vstakhov/libucl) -[](https://scan.coverity.com/projects/4138) -[](https://coveralls.io/github/vstakhov/libucl?branch=master) - -**Table of Contents** *generated with [DocToc](http://doctoc.herokuapp.com/)* - -- [Introduction](#introduction) -- [Basic structure](#basic-structure) -- [Improvements to the json notation](#improvements-to-the-json-notation) - - [General syntax sugar](#general-syntax-sugar) - - [Automatic arrays creation](#automatic-arrays-creation) - - [Named keys hierarchy](#named-keys-hierarchy) - - [Convenient numbers and booleans](#convenient-numbers-and-booleans) -- [General improvements](#general-improvements) - - [Comments](#comments) - - [Macros support](#macros-support) - - [Variables support](#variables-support) - - [Multiline strings](#multiline-strings) - - [Single quoted strings](#single-quoted-strings) -- [Emitter](#emitter) -- [Validation](#validation) -- [Performance](#performance) -- [Conclusion](#conclusion) - -## Introduction - -This document describes the main features and principles of the configuration -language called `UCL` - universal configuration language. - -If you are looking for the libucl API documentation you can find it at [this page](doc/api.md). - -## Basic structure - -UCL is heavily infused by `nginx` configuration as the example of a convenient configuration -system. However, UCL is fully compatible with `JSON` format and is able to parse json files. -For example, you can write the same configuration in the following ways: - -* in nginx like: - -```nginx -param = value; -section { - param = value; - param1 = value1; - flag = true; - number = 10k; - time = 0.2s; - string = "something"; - subsection { - host = { - host = "hostname"; - port = 900; - } - host = { - host = "hostname"; - port = 901; - } - } -} -``` - -* or in JSON: - -```json -{ - "param": "value", - "section": { - "param": "value", - "param1": "value1", - "flag": true, - "number": 10000, - "time": "0.2s", - "string": "something", - "subsection": { - "host": [ - { - "host": "hostname", - "port": 900 - }, - { - "host": "hostname", - "port": 901 - } - ] - } - } -} -``` - -## Improvements to the json notation. - -There are various things that make ucl configuration more convenient for editing than strict json: - -### General syntax sugar - -* Braces are not necessary to enclose a top object: it is automatically treated as an object: - -```json -"key": "value" -``` -is equal to: -```json -{"key": "value"} -``` - -* There is no requirement of quotes for strings and keys, moreover, `:` may be replaced `=` or even be skipped for objects: - -```nginx -key = value; -section { - key = value; -} -``` -is equal to: -```json -{ - "key": "value", - "section": { - "key": "value" - } -} -``` - -* No commas mess: you can safely place a comma or semicolon for the last element in an array or an object: - -```json -{ - "key1": "value", - "key2": "value", -} -``` -### Automatic arrays creation - -* Non-unique keys in an object are allowed and are automatically converted to the arrays internally: - -```json -{ - "key": "value1", - "key": "value2" -} -``` -is converted to: -```json -{ - "key": ["value1", "value2"] -} -``` - -### Named keys hierarchy - -UCL accepts named keys and organize them into objects hierarchy internally. Here is an example of this process: -```nginx -section "blah" { - key = value; -} -section foo { - key = value; -} -``` - -is converted to the following object: - -```nginx -section { - blah { - key = value; - } - foo { - key = value; - } -} -``` - -Plain definitions may be more complex and contain more than a single level of nested objects: - -```nginx -section "blah" "foo" { - key = value; -} -``` - -is presented as: - -```nginx -section { - blah { - foo { - key = value; - } - } -} -``` - -### Convenient numbers and booleans - -* Numbers can have suffixes to specify standard multipliers: - + `[kKmMgG]` - standard 10 base multipliers (so `1k` is translated to 1000) - + `[kKmMgG]b` - 2 power multipliers (so `1kb` is translated to 1024) - + `[s|min|d|w|y]` - time multipliers, all time values are translated to float number of seconds, for example `10min` is translated to 600.0 and `10ms` is translated to 0.01 -* Hexadecimal integers can be used by `0x` prefix, for example `key = 0xff`. However, floating point values can use decimal base only. -* Booleans can be specified as `true` or `yes` or `on` and `false` or `no` or `off`. -* It is still possible to treat numbers and booleans as strings by enclosing them in double quotes. - -## General improvements - -### Comments - -UCL supports different style of comments: - -* single line: `#` -* multiline: `/* ... */` - -Multiline comments may be nested: -```c -# Sample single line comment -/* - some comment - /* nested comment */ - end of comment -*/ -``` - -### Macros support - -UCL supports external macros both multiline and single line ones: -```nginx -.macro_name "sometext"; -.macro_name { - Some long text - .... -}; -``` - -Moreover, each macro can accept an optional list of arguments in braces. These -arguments themselves are the UCL object that is parsed and passed to a macro as -options: - -```nginx -.macro_name(param=value) "something"; -.macro_name(param={key=value}) "something"; -.macro_name(.include "params.conf") "something"; -.macro_name(#this is multiline macro -param = [value1, value2]) "something"; -.macro_name(key="()") "something"; -``` - -UCL also provide a convenient `include` macro to load content from another files -to the current UCL object. This macro accepts either path to file: - -```nginx -.include "/full/path.conf" -.include "./relative/path.conf" -.include "${CURDIR}/path.conf" -``` - -or URL (if ucl is built with url support provided by either `libcurl` or `libfetch`): - - .include "http://example.com/file.conf" - -`.include` macro supports a set of options: - -* `try` (default: **false**) - if this option is `true` than UCL treats errors on loading of -this file as non-fatal. For example, such a file can be absent but it won't stop the parsing -of the top-level document. -* `sign` (default: **false**) - if this option is `true` UCL loads and checks the signature for -a file from path named `<FILEPATH>.sig`. Trusted public keys should be provided for UCL API after -parser is created but before any configurations are parsed. -* `glob` (default: **false**) - if this option is `true` UCL treats the filename as GLOB pattern and load -all files that matches the specified pattern (normally the format of patterns is defined in `glob` manual page -for your operating system). This option is meaningless for URL includes. -* `url` (default: **true**) - allow URL includes. -* `path` (default: empty) - A UCL_ARRAY of directories to search for the include file. -Search ends after the first match, unless `glob` is true, then all matches are included. -* `prefix` (default false) - Put included contents inside an object, instead -of loading them into the root. If no `key` is provided, one is automatically generated based on each files basename() -* `key` (default: <empty string>) - Key to load contents of include into. If -the key already exists, it must be the correct type -* `target` (default: object) - Specify if the `prefix` `key` should be an -object or an array. -* `priority` (default: 0) - specify priority for the include (see below). -* `duplicate` (default: 'append') - specify policy of duplicates resolving: - - `append` - default strategy, if we have new object of higher priority then it replaces old one, if we have new object with less priority it is ignored completely, and if we have two duplicate objects with the same priority then we have a multi-value key (implicit array) - - `merge` - if we have object or array, then new keys are merged inside, if we have a plain object then an implicit array is formed (regardless of priorities) - - `error` - create error on duplicate keys and stop parsing - - `rewrite` - always rewrite an old value with new one (ignoring priorities) - -Priorities are used by UCL parser to manage the policy of objects rewriting during including other files -as following: - -* If we have two objects with the same priority then we form an implicit array -* If a new object has bigger priority then we overwrite an old one -* If a new object has lower priority then we ignore it - -By default, the priority of top-level object is set to zero (lowest priority). Currently, -you can define up to 16 priorities (from 0 to 15). Includes with bigger priorities will -rewrite keys from the objects with lower priorities as specified by the policy. The priority -of the top-level or any other object can be changed with the `.priority` macro, which has no -options and takes the new priority: - -``` -# Default priority: 0. -foo = 6 -.priority 5 -# The following will have priority 5. -bar = 6 -baz = 7 -# The following will be included with a priority of 3, 5, and 6 respectively. -.include(priority=3) "path.conf" -.include(priority=5) "equivalent-path.conf" -.include(priority=6) "highpriority-path.conf" -``` - -### Variables support - -UCL supports variables in input. Variables are registered by a user of the UCL parser and can be presented in the following forms: - -* `${VARIABLE}` -* `$VARIABLE` - -UCL currently does not support nested variables. To escape variables one could use double dollar signs: - -* `$${VARIABLE}` is converted to `${VARIABLE}` -* `$$VARIABLE` is converted to `$VARIABLE` - -However, if no valid variables are found in a string, no expansion will be performed (and `$$` thus remains unchanged). This may be a subject -to change in future libucl releases. - -### Multiline strings - -UCL can handle multiline strings as well as single line ones. It uses shell/perl like notation for such objects: -``` -key = <<EOD -some text -splitted to -lines -EOD -``` - -In this example `key` will be interpreted as the following string: `some text\nsplitted to\nlines`. -Here are some rules for this syntax: - -* Multiline terminator must start just after `<<` symbols and it must consist of capital letters only (e.g. `<<eof` or `<< EOF` won't work); -* Terminator must end with a single newline character (and no spaces are allowed between terminator and newline character); -* To finish multiline string you need to include a terminator string just after newline and followed by a newline (no spaces or other characters are allowed as well); -* The initial and the final newlines are not inserted to the resulting string, but you can still specify newlines at the beginning and at the end of a value, for example: - -``` -key <<EOD - -some -text - -EOD -``` - -### Single quoted strings - -It is possible to use single quoted strings to simplify escaping rules. All values passed in single quoted strings are *NOT* escaped, with two exceptions: a single `'` character just before `\` character, and a newline character just after `\` character that is ignored. - -``` -key = 'value'; # Read as value -key = 'value\n\'; # Read as value\n\ -key = 'value\''; # Read as value' -key = 'value\ -bla'; # Read as valuebla -``` - -## Emitter - -Each UCL object can be serialized to one of the four supported formats: - -* `JSON` - canonic json notation (with spaces indented structure); -* `Compacted JSON` - compact json notation (without spaces or newlines); -* `Configuration` - nginx like notation; -* `YAML` - yaml inlined notation. - -## Validation - -UCL allows validation of objects. It uses the same schema that is used for json: [json schema v4](http://json-schema.org). UCL supports the full set of json schema with the exception of remote references. This feature is unlikely useful for configuration objects. Of course, a schema definition can be in UCL format instead of JSON that simplifies schemas writing. Moreover, since UCL supports multiple values for keys in an object it is possible to specify generic integer constraints `maxValues` and `minValues` to define the limits of values count in a single key. UCL currently is not absolutely strict about validation schemas themselves, therefore UCL users should supply valid schemas (as it is defined in json-schema draft v4) to ensure that the input objects are validated properly. - -## Performance - -Are UCL parser and emitter fast enough? Well, there are some numbers. -I got a 19Mb file that consist of ~700 thousand lines of json (obtained via -http://www.json-generator.com/). Then I checked jansson library that performs json -parsing and emitting and compared it with UCL. Here are results: - -``` -jansson: parsed json in 1.3899 seconds -jansson: emitted object in 0.2609 seconds - -ucl: parsed input in 0.6649 seconds -ucl: emitted config in 0.2423 seconds -ucl: emitted json in 0.2329 seconds -ucl: emitted compact json in 0.1811 seconds -ucl: emitted yaml in 0.2489 seconds -``` - -So far, UCL seems to be significantly faster than jansson on parsing and slightly faster on emitting. Moreover, -UCL compiled with optimizations (-O3) performs significantly faster: -``` -ucl: parsed input in 0.3002 seconds -ucl: emitted config in 0.1174 seconds -ucl: emitted json in 0.1174 seconds -ucl: emitted compact json in 0.0991 seconds -ucl: emitted yaml in 0.1354 seconds -``` - -You can do your own benchmarks by running `make check` in libucl top directory. - -## Conclusion - -UCL has clear design that should be very convenient for reading and writing. At the same time it is compatible with -JSON language and therefore can be used as a simple JSON parser. Macro logic provides an ability to extend configuration -language (for example by including some lua code) and comments allow to disable or enable the parts of a configuration -quickly. diff --git a/contrib/libucl/autogen.sh b/contrib/libucl/autogen.sh deleted file mode 100755 index 68f4a174b46e..000000000000 --- a/contrib/libucl/autogen.sh +++ /dev/null @@ -1,2 +0,0 @@ -#!/bin/sh -autoreconf -i diff --git a/contrib/libucl/configure.ac b/contrib/libucl/configure.ac deleted file mode 100644 index 731b7113e689..000000000000 --- a/contrib/libucl/configure.ac +++ /dev/null @@ -1,188 +0,0 @@ -m4_define([maj_ver], [0]) -m4_define([med_ver], [8]) -m4_define([min_ver], [1]) -m4_define([so_version], [6:0:1]) -m4_define([ucl_version], [maj_ver.med_ver.min_ver]) - -AC_INIT([libucl],[ucl_version],[https://github.com/vstakhov/libucl],[libucl]) -AC_CONFIG_SRCDIR([configure.ac]) -AM_INIT_AUTOMAKE([1.11 foreign -Wall -Wportability no-dist-gzip dist-xz]) -m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])]) - -UCL_VERSION=ucl_version -SO_VERSION=so_version - -AC_SUBST(UCL_VERSION) -AC_SUBST(SO_VERSION) - -AC_PROG_CC_C99 -AM_PROG_CC_C_O -AM_PROG_AR -LT_INIT -AC_CONFIG_MACRO_DIR([m4]) -AC_CONFIG_HEADERS([config.h]) - -AC_C_CONST -AC_TYPE_SIZE_T - -AC_CHECK_HEADERS_ONCE([fcntl.h unistd.h]) -AC_TYPE_OFF_T -AC_FUNC_MMAP -AC_CHECK_HEADERS_ONCE([fcntl.h]) -AC_CHECK_HEADERS_ONCE([sys/types.h]) -AC_CHECK_HEADERS_ONCE([sys/stat.h]) -AC_CHECK_HEADERS_ONCE([sys/param.h]) -AC_CHECK_HEADERS_ONCE([sys/mman.h]) -AC_CHECK_HEADERS_ONCE([stdlib.h]) -AC_CHECK_HEADERS_ONCE([stddef.h]) -AC_CHECK_HEADERS_ONCE([stdarg.h]) -AC_CHECK_HEADERS_ONCE([stdbool.h]) -AC_CHECK_HEADERS_ONCE([stdint.h]) -AC_CHECK_HEADERS_ONCE([string.h]) -AC_CHECK_HEADERS_ONCE([strings.h]) -AC_CHECK_HEADERS_ONCE([unistd.h]) -AC_CHECK_HEADERS_ONCE([ctype.h]) -AC_CHECK_HEADERS_ONCE([errno.h]) -AC_CHECK_HEADERS_ONCE([limits.h]) -AC_CHECK_HEADERS_ONCE([libgen.h]) -AC_CHECK_HEADERS_ONCE([stdio.h]) -AC_CHECK_HEADERS_ONCE([float.h]) -AC_CHECK_HEADERS_ONCE([math.h]) -AC_CHECK_HEADERS_ONCE([endian.h sys/endian.h machine/endian.h]) - -dnl Example of default-disabled feature -AC_ARG_ENABLE([urls], AS_HELP_STRING([--enable-urls], - [Enable URLs fetch (requires libfetch or libcurl) @<:@default=no@:>@]), [], - [enable_urls=no]) -AC_ARG_ENABLE([regex], AS_HELP_STRING([--enable-regex], - [Enable regex checking for schema @<:@default=yes@:>@]), [], - [enable_regex=yes]) -AC_ARG_ENABLE([signatures], AS_HELP_STRING([--enable-signatures], - [Enable signatures check (requires openssl) @<:@default=no@:>@]), [], - [enable_signatures=no]) -AC_ARG_ENABLE([lua], AS_HELP_STRING([--enable-lua], - [Enable lua API build (requires lua libraries and headers) @<:@default=no@:>@]), [], - [enable_lua=no]) -AC_ARG_ENABLE([utils], - AS_HELP_STRING([--enable-utils], [Build and install utils @<:@default=no@:>@]), - [case "${enableval}" in - yes) utils=true ;; - no) utils=false ;; - *) AC_MSG_ERROR([bad value ${enableval} for --enable-utils]) ;; - esac],[utils=false]) -AM_CONDITIONAL([UTILS], [test x$utils = xtrue]) - -AS_IF([test "x$enable_signatures" = "xyes"], [ - AC_SEARCH_LIBS([CRYPTO_new_ex_data], [crypto], [ - AC_DEFINE(HAVE_OPENSSL, 1, [Define to 1 if you have the 'crypto' library (-lcrypto).]) - LIBCRYPTO_LIB="-lcrypto" - LIBS_EXTRA="${LIBS_EXTRA} -lcrypto" - ], [AC_MSG_ERROR([unable to find the CRYPTO_new_ex_data() function])]) -]) -AC_SUBST(LIBCRYPTO_LIB) -AC_PATH_PROG(PANDOC, pandoc, [/non/existent]) - -AC_SEARCH_LIBS([clock_gettime], [rt], [], [ - AC_CHECK_HEADER([mach/mach_time.h], [ - AC_DEFINE(HAVE_MACH_MACH_TIME_H, 1, [Define to 1 on Darwin]) - ], [AC_MSG_ERROR([unable to find clock_gettime or mach_absolute_time])]) -]) -AC_SEARCH_LIBS([remainder], [m], [], [AC_MSG_ERROR([unable to find remainder() function])]) - -AS_IF([test "x$enable_regex" = "xyes"], [ - AC_CHECK_HEADER([regex.h], [ - AC_DEFINE(HAVE_REGEX_H, 1, [Define to 1 if you have the <regex.h> header file.]) - AC_SEARCH_LIBS([regexec], [regex], [ - AS_IF([test "x$ac_cv_search_regexec" = "x-lregex"], [ - LIBREGEX_LIB="-lregex" - LIBS_EXTRA="${LIBS_EXTRA} -lregex" - ] - )], - [AC_MSG_ERROR([unable to find the regexec() function])])], - [AC_MSG_ERROR([unable to find the regex.h header]) - ], - [#include <sys/types.h>]) -]) -AC_SUBST(LIBREGEX_LIB) - -AS_IF([test "x$enable_lua" = "xyes"], [ - AX_PROG_LUA([5.1], [], [ - AX_LUA_HEADERS([ - AX_LUA_LIBS([ - AC_DEFINE(HAVE_LUA, 1, [Define to 1 for lua support.]) - with_lua="yes" - ], [AC_MSG_ERROR([unable to find the lua libraries]) - ]) - ], [AC_MSG_ERROR([unable to find the lua header files]) - ]) - ], [AC_MSG_ERROR([unable to find the lua interpreter])]) -], [with_lua="no"]) - -AM_CONDITIONAL([LUA_SUB], [test "$with_lua" = "yes"]) - -AS_IF([test "x$enable_urls" = "xyes"], [ - AC_CHECK_HEADER([fetch.h], [ - AC_DEFINE(HAVE_FETCH_H, 1, [Define to 1 if you have the <fetch.h> header file.]) - AC_CHECK_LIB(fetch, fetchXGet, [ - AC_DEFINE(HAVE_LIBFETCH, 1, [Define to 1 if you have the 'fetch' library (-lfetch).]) - LIBFETCH_LIBS="-lfetch" - have_libfetch="yes" - LIBS_EXTRA="${LIBS_EXTRA} -lfetch" - ]) - ], [],[ - #include <stdio.h> - #ifdef HAVE_SYS_PARAM_H - #include <sys/param.h> - #endif - ]) - AC_SUBST(LIBFETCH_LIBS) - - AS_IF([ test "x$have_libfetch" != "xyes"], [ - dnl Fallback to libcurl - PKG_CHECK_MODULES([CURL], [libcurl], [ - AC_DEFINE(CURL_FOUND, 1, [Use libcurl]) - LIBS_EXTRA="${LIBS_EXTRA} -lcurl"], - [AC_MSG_ERROR([unable to find neither libfetch nor libcurl])]) - ]) - AC_SUBST(CURL_FOUND) - AC_SUBST(CURL_LIBS) - AC_SUBST(CURL_CFLAGS) -]) - -AC_SUBST(LIBS_EXTRA) - -AC_MSG_CHECKING(for GCC atomic builtins) -AC_LINK_IFELSE([ - AC_LANG_SOURCE([[ - int main() { - volatile unsigned long val = 1; - __sync_synchronize(); - __sync_val_compare_and_swap(&val, 1, 0); - __sync_add_and_fetch(&val, 1); - __sync_sub_and_fetch(&val, 1); - return 0; - } - ]]) -], -[ - AC_MSG_RESULT([yes]) - AC_DEFINE([HAVE_ATOMIC_BUILTINS], [1], [Has gcc/MSVC atomic intrinsics]) -], -[ - AC_MSG_RESULT([no]) - AC_DEFINE([HAVE_ATOMIC_BUILTINS], [0], [Has gcc/MSVC atomic intrinsics]) - AC_MSG_WARN([Libucl references could be thread-unsafe because atomic builtins are missing]) -]) - -AX_CODE_COVERAGE - -AC_CONFIG_FILES(Makefile \ - src/Makefile \ - lua/Makefile - tests/Makefile \ - utils/Makefile \ - doc/Makefile \ - lua/libucl.rockspec \ - libucl.pc) -AC_CONFIG_FILES([stamp-h], [echo timestamp > stamp-h]) -AC_OUTPUT diff --git a/contrib/libucl/doc/Makefile.am b/contrib/libucl/doc/Makefile.am deleted file mode 100644 index dcfacf6a9a25..000000000000 --- a/contrib/libucl/doc/Makefile.am +++ /dev/null @@ -1,9 +0,0 @@ -EXTRA_DIST = api.md - -dist_man_MANS = libucl.3 - -gen-man: @PANDOC@ - tail -n +$$(grep -n '# Synopsis' api.md | cut -d':' -f1) api.md | \ - cat pandoc.template - | sed -e 's/^# \(.*\)/# \U\1/' \ - -e "s/%%date%%/$$(LANG=C date +'%d %B, %Y')/" | \ - @PANDOC@ -s -f markdown -t man -o libucl.3 diff --git a/contrib/libucl/doc/api.md b/contrib/libucl/doc/api.md deleted file mode 100644 index a0d33c0e68a9..000000000000 --- a/contrib/libucl/doc/api.md +++ /dev/null @@ -1,506 +0,0 @@ -# API documentation - -**Table of Contents** *generated with [DocToc](http://doctoc.herokuapp.com/)* - -- [Synopsis](#synopsis) -- [Description](#description) - - [Parser functions](#parser-functions) - - [Emitting functions](#emitting-functions) - - [Conversion functions](#conversion-functions) - - [Generation functions](#generation-functions) - - [Iteration functions](#iteration-functions) - - [Validation functions](#validation-functions) - - [Utility functions](#utility-functions) -- [Parser functions](#parser-functions-1) - - [ucl_parser_new](#ucl_parser_new) - - [ucl_parser_register_macro](#ucl_parser_register_macro) - - [ucl_parser_register_variable](#ucl_parser_register_variable) - - [ucl_parser_add_chunk](#ucl_parser_add_chunk) - - [ucl_parser_add_string](#ucl_parser_add_string) - - [ucl_parser_add_file](#ucl_parser_add_file) - - [ucl_parser_get_object](#ucl_parser_get_object) - - [ucl_parser_get_error](#ucl_parser_get_error) - - [ucl_parser_free](#ucl_parser_free) - - [ucl_pubkey_add](#ucl_pubkey_add) - - [ucl_parser_set_filevars](#ucl_parser_set_filevars) - - [Parser usage example](#parser-usage-example) -- [Emitting functions](#emitting-functions-1) - - [ucl_object_emit](#ucl_object_emit) - - [ucl_object_emit_full](#ucl_object_emit_full) -- [Conversion functions](#conversion-functions-1) -- [Generation functions](#generation-functions-1) - - [ucl_object_new](#ucl_object_new) - - [ucl_object_typed_new](#ucl_object_typed_new) - - [Primitive objects generation](#primitive-objects-generation) - - [ucl_object_fromstring_common](#ucl_object_fromstring_common) -- [Iteration functions](#iteration-functions-1) - - [ucl_iterate_object](#ucl_iterate_object) -- [Validation functions](#validation-functions-1) - - [ucl_object_validate](#ucl_object_validate) - -# Synopsis - -`#include <ucl.h>` - -# Description - -Libucl is a parser and `C` API to parse and generate `ucl` objects. Libucl consist of several groups of functions: - -### Parser functions -Used to parse `ucl` files and provide interface to extract `ucl` object. Currently, `libucl` can parse only full `ucl` documents, for instance, it is impossible to parse a part of document and therefore it is impossible to use `libucl` as a streaming parser. In future, this limitation can be removed. - -### Emitting functions -Convert `ucl` objects to some textual or binary representation. Currently, libucl supports the following exports: - -- `JSON` - valid json format (can possibly lose some original data, such as implicit arrays) -- `Config` - human-readable configuration format (lossless) -- `YAML` - embedded yaml format (has the same limitations as `json` output) - -### Conversion functions -Help to convert `ucl` objects to C types. These functions are used to convert `ucl_object_t` to C primitive types, such as numbers, strings or boolean values. - -### Generation functions -Allow creation of `ucl` objects from C types and creating of complex `ucl` objects, such as hashes or arrays from primitive `ucl` objects, such as numbers or strings. - -### Iteration functions -Iterate over `ucl` complex objects or over a chain of values, for example when a key in an object has multiple values (that can be treated as implicit array or implicit consolidation). - -### Validation functions -Validation functions are used to validate some object `obj` using json-schema compatible object `schema`. Both input and schema must be UCL objects to perform validation. - -### Utility functions -Provide basic utilities to manage `ucl` objects: creating, removing, retaining and releasing reference count and so on. - -# Parser functions - -Parser functions operates with `struct ucl_parser`. - -### ucl_parser_new - -~~~C -struct ucl_parser* ucl_parser_new (int flags); -~~~ - -Creates new parser with the specified flags: - -- `UCL_PARSER_KEY_LOWERCASE` - lowercase keys parsed -- `UCL_PARSER_ZEROCOPY` - try to use zero-copy mode when reading files (in zero-copy mode text chunk being parsed without copying strings so it should exist till any object parsed is used) -- `UCL_PARSER_NO_TIME` - treat time values as strings without parsing them as floats - -### ucl_parser_register_macro - -~~~C -void ucl_parser_register_macro (struct ucl_parser *parser, - const char *macro, ucl_macro_handler handler, void* ud); -~~~ - -Register new macro with name .`macro` parsed by handler `handler` that accepts opaque data pointer `ud`. Macro handler should be of the following type: - -~~~C -bool (*ucl_macro_handler) (const unsigned char *data, - size_t len, void* ud);` -~~~ - -Handler function accepts macro text `data` of length `len` and the opaque pointer `ud`. If macro is parsed successfully the handler should return `true`. `false` indicates parsing failure and the parser can be terminated. - -### ucl_parser_register_variable - -~~~C -void ucl_parser_register_variable (struct ucl_parser *parser, - const char *var, const char *value); -~~~ - -Register new variable $`var` that should be replaced by the parser to the `value` string. - -### ucl_parser_add_chunk - -~~~C -bool ucl_parser_add_chunk (struct ucl_parser *parser, - const unsigned char *data, size_t len); -~~~ - -Add new text chunk with `data` of length `len` to the parser. At the moment, `libucl` parser is not a streamlined parser and chunk *must* contain the *valid* ucl object. For example, this object should be valid: - -~~~json -{ "var": "value" } -~~~ - -while this one won't be parsed correctly: - -~~~json -{ "var": -~~~ - -This limitation may possible be removed in future. - -### ucl_parser_add_string -~~~C -bool ucl_parser_add_string (struct ucl_parser *parser, - const char *data, size_t len); -~~~ - -This function acts exactly like `ucl_parser_add_chunk` does but if `len` argument is zero, then the string `data` must be zero-terminated and the actual length is calculated up to `\0` character. - -### ucl_parser_add_file - -~~~C -bool ucl_parser_add_file (struct ucl_parser *parser, - const char *filename); -~~~ - -Load file `filename` and parse it with the specified `parser`. This function uses `mmap` call to load file, therefore, it should not be `shrunk` during parsing. Otherwise, `libucl` can cause memory corruption and terminate the calling application. This function is also used by the internal handler of `include` macro, hence, this macro has the same limitation. - -### ucl_parser_get_object - -~~~C -ucl_object_t* ucl_parser_get_object (struct ucl_parser *parser); -~~~ - -If the `ucl` data has been parsed correctly this function returns the top object for the parser. Otherwise, this function returns the `NULL` pointer. The reference count for `ucl` object returned is increased by one, therefore, a caller should decrease reference by using `ucl_object_unref` to free object after usage. - -### ucl_parser_get_error - -~~~C -const char *ucl_parser_get_error(struct ucl_parser *parser); -~~~ - -Returns the constant error string for the parser object. If no error occurred during parsing a `NULL` object is returned. A caller should not try to free or modify this string. - -### ucl_parser_free - -~~~C -void ucl_parser_free (struct ucl_parser *parser); -~~~ - -Frees memory occupied by the parser object. The reference count for top object is decreased as well, however if the function `ucl_parser_get_object` was called previously then the top object won't be freed. - -### ucl_pubkey_add - -~~~C -bool ucl_pubkey_add (struct ucl_parser *parser, - const unsigned char *key, size_t len); -~~~ - -This function adds a public key from text blob `key` of length `len` to the `parser` object. This public key should be in the `PEM` format and can be used by `.includes` macro for checking signatures of files included. `Openssl` support should be enabled to make this function working. If a key cannot be added (e.g. due to format error) or `openssl` was not linked to `libucl` then this function returns `false`. - -### ucl_parser_set_filevars - -~~~C -bool ucl_parser_set_filevars (struct ucl_parser *parser, - const char *filename, bool need_expand); -~~~ - -Add the standard file variables to the `parser` based on the `filename` specified: - -- `$FILENAME` - a filename of `ucl` input -- `$CURDIR` - a current directory of the input - -For example, if a `filename` param is `../something.conf` then the variables will have the following values: - -- `$FILENAME` - "../something.conf" -- `$CURDIR` - ".." - -if `need_expand` parameter is `true` then all relative paths are expanded using `realpath` call. In this example if `..` is `/etc/dir` then variables will have these values: - -- `$FILENAME` - "/etc/something.conf" -- `$CURDIR` - "/etc" - -## Parser usage example - -The following example loads, parses and extracts `ucl` object from stdin using `libucl` parser functions (the length of input is limited to 8K): - -~~~C -char inbuf[8192]; -struct ucl_parser *parser = NULL; -int ret = 0, r = 0; -ucl_object_t *obj = NULL; -FILE *in; - -in = stdin; -parser = ucl_parser_new (0); -while (!feof (in) && r < (int)sizeof (inbuf)) { - r += fread (inbuf + r, 1, sizeof (inbuf) - r, in); -} -ucl_parser_add_chunk (parser, inbuf, r); -fclose (in); - -if (ucl_parser_get_error (parser)) { - printf ("Error occurred: %s\n", ucl_parser_get_error (parser)); - ret = 1; -} -else { - obj = ucl_parser_get_object (parser); -} - -if (parser != NULL) { - ucl_parser_free (parser); -} -if (obj != NULL) { - ucl_object_unref (obj); -} -return ret; -~~~ - -# Emitting functions - -Libucl can transform UCL objects to a number of textual formats: - -- configuration (`UCL_EMIT_CONFIG`) - nginx like human readable configuration file where implicit arrays are transformed to the duplicate keys -- compact json: `UCL_EMIT_JSON_COMPACT` - single line valid json without spaces -- formatted json: `UCL_EMIT_JSON` - pretty formatted JSON with newlines and spaces -- compact yaml: `UCL_EMIT_YAML` - compact YAML output - -Moreover, libucl API allows to select a custom set of emitting functions allowing -efficient and zero-copy output of libucl objects. Libucl uses the following structure to support this feature: - -~~~C -struct ucl_emitter_functions { - /** Append a single character */ - int (*ucl_emitter_append_character) (unsigned char c, size_t nchars, void *ud); - /** Append a string of a specified length */ - int (*ucl_emitter_append_len) (unsigned const char *str, size_t len, void *ud); - /** Append a 64 bit integer */ - int (*ucl_emitter_append_int) (int64_t elt, void *ud); - /** Append floating point element */ - int (*ucl_emitter_append_double) (double elt, void *ud); - /** Opaque userdata pointer */ - void *ud; -}; -~~~ - -This structure defines the following callbacks: - -- `ucl_emitter_append_character` - a function that is called to append `nchars` characters equal to `c` -- `ucl_emitter_append_len` - used to append a string of length `len` starting from pointer `str` -- `ucl_emitter_append_int` - this function applies to integer numbers -- `ucl_emitter_append_double` - this function is intended to output floating point variable - -The set of these functions could be used to output text formats of `UCL` objects to different structures or streams. - -Libucl provides the following functions for emitting UCL objects: - -### ucl_object_emit - -~~~C -unsigned char *ucl_object_emit (const ucl_object_t *obj, enum ucl_emitter emit_type); -~~~ - -Allocate a string that is suitable to fit the underlying UCL object `obj` and fill it with the textual representation of the object `obj` according to style `emit_type`. The caller should free the returned string after using. - -### ucl_object_emit_full - -~~~C -bool ucl_object_emit_full (const ucl_object_t *obj, enum ucl_emitter emit_type, - struct ucl_emitter_functions *emitter); -~~~ - -This function is similar to the previous with the exception that it accepts the additional argument `emitter` that defines the concrete set of output functions. This emit function could be useful for custom structures or streams emitters (including C++ ones, for example). - -# Conversion functions - -Conversion functions are used to convert UCL objects to primitive types, such as strings, numbers, or boolean values. There are two types of conversion functions: - -- safe: try to convert an ucl object to a primitive type and fail if such a conversion is not possible -- unsafe: return primitive type without additional checks, if the object cannot be converted then some reasonable default is returned (NULL for strings and 0 for numbers) - -Also there is a single `ucl_object_tostring_forced` function that converts any UCL object (including compound types - arrays and objects) to a string representation. For objects, arrays, booleans and numeric types this function performs emitting to a compact json format actually. - -Here is a list of all conversion functions: - -- `ucl_object_toint` - returns `int64_t` of UCL object -- `ucl_object_todouble` - returns `double` of UCL object -- `ucl_object_toboolean` - returns `bool` of UCL object -- `ucl_object_tostring` - returns `const char *` of UCL object (this string is NULL terminated) -- `ucl_object_tolstring` - returns `const char *` and `size_t` len of UCL object (string does not need to be NULL terminated) -- `ucl_object_tostring_forced` - returns string representation of any UCL object - -Strings returned by these pointers are associated with the UCL object and exist over its lifetime. A caller should not free this memory. - -# Generation functions - -It is possible to generate UCL objects from C primitive types. Moreover, libucl allows creation and modifying complex UCL objects, such as arrays or associative objects. - -## ucl_object_new -~~~C -ucl_object_t * ucl_object_new (void) -~~~ - -Creates new object of type `UCL_NULL`. This object should be released by caller. - -## ucl_object_typed_new -~~~C -ucl_object_t * ucl_object_typed_new (unsigned int type) -~~~ - -Create an object of a specified type: -- `UCL_OBJECT` - UCL object - key/value pairs -- `UCL_ARRAY` - UCL array -- `UCL_INT` - integer number -- `UCL_FLOAT` - floating point number -- `UCL_STRING` - NULL terminated string -- `UCL_BOOLEAN` - boolean value -- `UCL_TIME` - time value (floating point number of seconds) -- `UCL_USERDATA` - opaque userdata pointer (may be used in macros) -- `UCL_NULL` - null value - -This object should be released by caller. - -## Primitive objects generation -Libucl provides the functions similar to inverse conversion functions called with the specific C type: -- `ucl_object_fromint` - converts `int64_t` to UCL object -- `ucl_object_fromdouble` - converts `double` to UCL object -- `ucl_object_frombool` - converts `bool` to UCL object -- `ucl_object_fromstring` - converts `const char *` to UCL object (this string should be NULL terminated) -- `ucl_object_fromlstring` - converts `const char *` and `size_t` len to UCL object (string does not need to be NULL terminated) - -Also there is a function to generate UCL object from a string performing various parsing or conversion operations called `ucl_object_fromstring_common`. - -## ucl_object_fromstring_common -~~~C -ucl_object_t * ucl_object_fromstring_common (const char *str, - size_t len, enum ucl_string_flags flags) -~~~ - -This function is used to convert a string `str` of size `len` to a UCL object applying `flags` conversions. If `len` is equal to zero then a `str` is assumed as NULL-terminated. This function supports the following flags (a set of flags can be specified using logical `OR` operation): - -- `UCL_STRING_ESCAPE` - perform JSON escape -- `UCL_STRING_TRIM` - trim leading and trailing whitespaces -- `UCL_STRING_PARSE_BOOLEAN` - parse passed string and detect boolean -- `UCL_STRING_PARSE_INT` - parse passed string and detect integer number -- `UCL_STRING_PARSE_DOUBLE` - parse passed string and detect integer or float number -- `UCL_STRING_PARSE_TIME` - parse time values as floating point numbers -- `UCL_STRING_PARSE_NUMBER` - parse passed string and detect number (both float, integer and time types) -- `UCL_STRING_PARSE` - parse passed string (and detect booleans, numbers and time values) -- `UCL_STRING_PARSE_BYTES` - assume that numeric multipliers are in bytes notation, for example `10k` means `10*1024` and not `10*1000` as assumed without this flag - -If parsing operations fail then the resulting UCL object will be a `UCL_STRING`. A caller should always check the type of the returned object and release it after using. - -# Iteration functions - -Iteration are used to iterate over UCL compound types: arrays and objects. Moreover, iterations could be performed over the keys with multiple values (implicit arrays). -There are two types of iterators API: old and unsafe one via `ucl_iterate_object` and the proposed interface of safe iterators. - - -## ucl_iterate_object -~~~C -const ucl_object_t* ucl_iterate_object (const ucl_object_t *obj, - ucl_object_iter_t *iter, bool expand_values); -~~~ - -This function accepts opaque iterator pointer `iter`. In the first call this iterator *must* be initialized to `NULL`. Iterator is changed by this function call. `ucl_iterate_object` returns the next UCL object in the compound object `obj` or `NULL` if all objects have been iterated. The reference count of the object returned is not increased, so a caller should not unref the object or modify its content (e.g. by inserting to another compound object). The object `obj` should not be changed during the iteration process as well. `expand_values` flag speicifies whether `ucl_iterate_object` should expand keys with multiple values. The general rule is that if you need to iterate through the *object* or *explicit array*, then you always need to set this flag to `true`. However, if you get some key in the object and want to extract all its values then you should set `expand_values` to `false`. Mixing of iteration types is not permitted since the iterator is set according to the iteration type and cannot be reused. Here is an example of iteration over the objects using libucl API (assuming that `top` is `UCL_OBJECT` in this example): - -~~~C -ucl_object_iter_t it = NULL, it_obj = NULL; -const ucl_object_t *cur, *tmp; - -/* Iterate over the object */ -while ((obj = ucl_iterate_object (top, &it, true))) { - printf ("key: \"%s\"\n", ucl_object_key (obj)); - /* Iterate over the values of a key */ - while ((cur = ucl_iterate_object (obj, &it_obj, false))) { - printf ("value: \"%s\"\n", - ucl_object_tostring_forced (cur)); - } -} -~~~ - -## Safe iterators API - -Safe iterators are defined to clarify iterating over UCL objects and simplify flattening of UCL objects in non-trivial cases. -For example, if there is an implicit array that contains another array and a boolean value it is extremely unclear how to iterate over -such an object. Safe iterators are desinged to define two sorts of iteration: - -1. Iteration over complex objects with expanding all values -2. Iteration over complex objects without expanding of values - -The following example demonstrates the difference between these two types of iteration: - -~~~ -key = 1; -key = [2, 3, 4]; - -Iteration with expansion: - -1, 2, 3, 4 - -Iteration without expansion: - -1, [2, 3, 4] -~~~ - -UCL defines the following functions to manage safe iterators: - -- `ucl_object_iterate_new` - creates new safe iterator -- `ucl_object_iterate_reset` - resets iterator to a new object -- `ucl_object_iterate_safe` - safely iterate the object inside iterator. Note: function may allocate and free memory during its operation. Therefore it returns `NULL` either while trying to access item after the last one or when exception (such as memory allocation failure) happens. -- `ucl_object_iter_chk_excpn` - check if the last call to `ucl_object_iterate_safe` ended up in unrecoverable exception (e.g. `ENOMEM`). -- `ucl_object_iterate_free` - free memory associated with the safe iterator - -Please note that unlike unsafe iterators, safe iterators *must* be explicitly initialized and freed. -An assert is likely generated if you use uninitialized or `NULL` iterator in all safe iterators functions. - -~~~C -ucl_object_iter_t it; -const ucl_object_t *cur; - -it = ucl_object_iterate_new (obj); - -while ((cur = ucl_object_iterate_safe (it, true)) != NULL) { - /* Do something */ -} -/* Check error condition */ -if (ucl_object_iter_chk_excpn (it)) { - ucl_object_iterate_free (it); - exit (1); -} - -/* Switch to another object */ -it = ucl_object_iterate_reset (it, another_obj); - -while ((cur = ucl_object_iterate_safe (it, true)) != NULL) { - /* Do something else */ -} -/* Check error condition */ -if (ucl_object_iter_chk_excpn (it)) { - ucl_object_iterate_free (it); - exit (1); -} - -ucl_object_iterate_free (it); -~~~ - -# Validation functions - -Currently, there is only one validation function called `ucl_object_validate`. It performs validation of object using the specified schema. This function is defined as following: - -## ucl_object_validate -~~~C -bool ucl_object_validate (const ucl_object_t *schema, - const ucl_object_t *obj, struct ucl_schema_error *err); -~~~ - -This function uses ucl object `schema`, that must be valid in terms of `json-schema` draft v4, to validate input object `obj`. If this function returns `true` then validation procedure has been succeed. Otherwise, `false` is returned and `err` is set to a specific value. If a caller sets `err` to NULL then this function does not set any error just returning `false`. Error is the structure defined as following: - -~~~C -struct ucl_schema_error { - enum ucl_schema_error_code code; /* error code */ - char msg[128]; /* error message */ - ucl_object_t *obj; /* object where error occurred */ -}; -~~~ - -Caller may use `code` field to get a numeric error code: - -~~~C -enum ucl_schema_error_code { - UCL_SCHEMA_OK = 0, /* no error */ - UCL_SCHEMA_TYPE_MISMATCH, /* type of object is incorrect */ - UCL_SCHEMA_INVALID_SCHEMA, /* schema is invalid */ - UCL_SCHEMA_MISSING_PROPERTY,/* missing properties */ - UCL_SCHEMA_CONSTRAINT, /* constraint found */ - UCL_SCHEMA_MISSING_DEPENDENCY, /* missing dependency */ - UCL_SCHEMA_UNKNOWN /* generic error */ -}; -~~~ - -`msg` is a string description of an error and `obj` is an object where error has occurred. Error object is not allocated by libucl, so there is no need to free it after validation (a static object should thus be used). diff --git a/contrib/libucl/doc/lua_api.md b/contrib/libucl/doc/lua_api.md deleted file mode 100644 index 7da414903b01..000000000000 --- a/contrib/libucl/doc/lua_api.md +++ /dev/null @@ -1,196 +0,0 @@ -## Module `ucl` - -This lua module allows to parse objects from strings and to store data into -ucl objects. It uses `libucl` C library to parse and manipulate with ucl objects. - -Example: - -~~~lua -local ucl = require("ucl") - -local parser = ucl.parser() -local res,err = parser:parse_string('{key=value}') - -if not res then - print('parser error: ' .. err) -else - local obj = parser:get_object() - local got = ucl.to_format(obj, 'json') -end - -local table = { - str = 'value', - num = 100500, - null = ucl.null, - func = function () - return 'huh' - end -} - - -print(ucl.to_format(table, 'ucl')) --- Output: ---[[ -num = 100500; -str = "value"; -null = null; -func = "huh"; ---]] -~~~ - -###Brief content: - -**Functions**: - -> [`ucl_object_push_lua(L, obj, allow_array)`](#function-ucl_object_push_lual-obj-allow_array) - -> [`ucl.to_format(var, format)`](#function-uclto_formatvar-format) - - - -**Methods**: - -> [`parser:parse_file(name)`](#method-parserparse_filename) - -> [`parser:parse_string(input)`](#method-parserparse_stringinput) - -> [`parser:get_object()`](#method-parserget_object) - - -## Functions - -The module `ucl` defines the following functions. - -### Function `ucl_object_push_lua(L, obj, allow_array)` - -This is a `C` function to push `UCL` object as lua variable. This function -converts `obj` to lua representation using the following conversions: - -- *scalar* values are directly presented by lua objects -- *userdata* values are converted to lua function objects using `LUA_REGISTRYINDEX`, -this can be used to pass functions from lua to c and vice-versa -- *arrays* are converted to lua tables with numeric indices suitable for `ipairs` iterations -- *objects* are converted to lua tables with string indices - -**Parameters:** - -- `L {lua_State}`: lua state pointer -- `obj {ucl_object_t}`: object to push -- `allow_array {bool}`: expand implicit arrays (should be true for all but partial arrays) - -**Returns:** - -- `{int}`: `1` if an object is pushed to lua - -Back to [module description](#module-ucl). - -### Function `ucl.to_format(var, format)` - -Converts lua variable `var` to the specified `format`. Formats supported are: - -- `json` - fine printed json -- `json-compact` - compacted json -- `config` - fine printed configuration -- `ucl` - same as `config` -- `yaml` - embedded yaml - -If `var` contains function, they are called during output formatting and if -they return string value, then this value is used for ouptut. - -**Parameters:** - -- `var {variant}`: any sort of lua variable (if userdata then metafield `__to_ucl` is searched for output) -- `format {string}`: any available format - -**Returns:** - -- `{string}`: string representation of `var` in the specific `format`. - -Example: - -~~~lua -local table = { - str = 'value', - num = 100500, - null = ucl.null, - func = function () - return 'huh' - end -} - - -print(ucl.to_format(table, 'ucl')) --- Output: ---[[ -num = 100500; -str = "value"; -null = null; -func = "huh"; ---]] -~~~ - -Back to [module description](#module-ucl). - - -## Methods - -The module `ucl` defines the following methods. - -### Method `parser:parse_file(name)` - -Parse UCL object from file. - -**Parameters:** - -- `name {string}`: filename to parse - -**Returns:** - -- `{bool[, string]}`: if res is `true` then file has been parsed successfully, otherwise an error string is also returned - -Example: - -~~~lua -local parser = ucl.parser() -local res,err = parser:parse_file('/some/file.conf') - -if not res then - print('parser error: ' .. err) -else - -- Do something with object -end -~~~ - -Back to [module description](#module-ucl). - -### Method `parser:parse_string(input)` - -Parse UCL object from file. - -**Parameters:** - -- `input {string}`: string to parse - -**Returns:** - -- `{bool[, string]}`: if res is `true` then file has been parsed successfully, otherwise an error string is also returned - -Back to [module description](#module-ucl). - -### Method `parser:get_object()` - -Get top object from parser and export it to lua representation. - -**Parameters:** - - nothing - -**Returns:** - -- `{variant or nil}`: ucl object as lua native variable - -Back to [module description](#module-ucl). - - -Back to [top](#). - diff --git a/contrib/libucl/doc/pandoc.template b/contrib/libucl/doc/pandoc.template deleted file mode 100644 index 2effe1a157ef..000000000000 --- a/contrib/libucl/doc/pandoc.template +++ /dev/null @@ -1,12 +0,0 @@ -% LIBUCL(3) Libucl manual -% Vsevolod Stakhov <vsevolod@highsecure.ru> -% %%date%% - -# Name - -**ucl_parser_new**, **ucl_parser_register_macro**, **ucl_parser_register_variable**, **ucl_parser_add_chunk**, **ucl_parser_add_string**, **ucl_parser_add_file**, **ucl_parser_get_object**, **ucl_parser_get_error**, **ucl_parser_free**, **ucl_pubkey_add**, **ucl_parser_set_filevars** - universal configuration library parser and utility functions - -# Library - -UCL library (libucl, -lucl) - diff --git a/contrib/libucl/examples/ucl_cpp.cc b/contrib/libucl/examples/ucl_cpp.cc deleted file mode 100644 index 2d15d84a6c8d..000000000000 --- a/contrib/libucl/examples/ucl_cpp.cc +++ /dev/null @@ -1,26 +0,0 @@ -#include <iostream> -#include <string> -#include "ucl++.h" - -int main(int argc, char **argv) -{ - std::string input, err; - - input.assign((std::istreambuf_iterator<char>(std::cin)), - std::istreambuf_iterator<char>()); - - auto obj = ucl::Ucl::parse(input, err); - - if (obj) { - std::cout << obj.dump(UCL_EMIT_CONFIG) << std::endl; - - for (const auto &o : obj) { - std::cout << o.dump(UCL_EMIT_CONFIG) << std::endl; - } - } - else { - std::cerr << "Error: " << err << std::endl; - - return 1; - } -} diff --git a/contrib/libucl/haskell/hucl.hs b/contrib/libucl/haskell/hucl.hs deleted file mode 100644 index 2dd3ac01e4c0..000000000000 --- a/contrib/libucl/haskell/hucl.hs +++ /dev/null @@ -1,123 +0,0 @@ -{-# LANGUAGE ForeignFunctionInterface #-} - --- an example UCL FFI module: --- uses the Object Model from Messagepack to emit --- - -module Data.UCL ( unpack ) where -import Foreign.C -import Foreign.Ptr -import System.IO.Unsafe ( unsafePerformIO ) -import qualified Data.Text as T -import qualified Data.Vector as V -import qualified Data.MessagePack as MSG - -type ParserHandle = Ptr () -type UCLObjectHandle = Ptr () -type UCLIterHandle = Ptr () -type UCLEmitterType = CInt -type ErrorString = String - - -foreign import ccall "ucl_parser_new" ucl_parser_new :: CInt -> ParserHandle -foreign import ccall "ucl_parser_add_string" ucl_parser_add_string :: ParserHandle -> CString -> CUInt -> IO Bool -foreign import ccall "ucl_parser_add_file" ucl_parser_add_file :: ParserHandle -> CString -> IO Bool -foreign import ccall "ucl_parser_get_object" ucl_parser_get_object :: ParserHandle -> UCLObjectHandle -foreign import ccall "ucl_parser_get_error" ucl_parser_get_error :: ParserHandle -> CString - -foreign import ccall "ucl_object_iterate_new" ucl_object_iterate_new :: UCLObjectHandle -> UCLIterHandle -foreign import ccall "ucl_object_iterate_safe" ucl_object_iterate_safe :: UCLIterHandle -> Bool -> UCLObjectHandle -foreign import ccall "ucl_object_type" ucl_object_type :: UCLObjectHandle -> CUInt -foreign import ccall "ucl_object_key" ucl_object_key :: UCLObjectHandle -> CString -foreign import ccall "ucl_object_toint" ucl_object_toint :: UCLObjectHandle -> CInt -foreign import ccall "ucl_object_todouble" ucl_object_todouble :: UCLObjectHandle -> CDouble -foreign import ccall "ucl_object_tostring" ucl_object_tostring :: UCLObjectHandle -> CString -foreign import ccall "ucl_object_toboolean" ucl_object_toboolean :: UCLObjectHandle -> Bool - -foreign import ccall "ucl_object_emit" ucl_object_emit :: UCLObjectHandle -> UCLEmitterType -> CString -foreign import ccall "ucl_object_emit_len" ucl_object_emit_len :: UCLObjectHandle -> UCLEmitterType -> Ptr CSize -> IO CString - -type UCL_TYPE = CUInt -ucl_OBJECT :: UCL_TYPE -ucl_OBJECT = 0 -ucl_ARRAY :: UCL_TYPE -ucl_ARRAY = 1 -ucl_INT :: UCL_TYPE -ucl_INT = 2 -ucl_FLOAT :: UCL_TYPE -ucl_FLOAT = 3 -ucl_STRING :: UCL_TYPE -ucl_STRING = 4 -ucl_BOOLEAN :: UCL_TYPE -ucl_BOOLEAN = 5 -ucl_TIME :: UCL_TYPE -ucl_TIME = 6 -ucl_USERDATA :: UCL_TYPE -ucl_USERDATA = 7 -ucl_NULL :: UCL_TYPE -ucl_NULL = 8 - -ucl_emit_json :: UCLEmitterType -ucl_emit_json = 0 -ucl_emit_json_compact :: UCLEmitterType -ucl_emit_json_compact = 1 :: UCLEmitterType -ucl_emit_msgpack :: UCLEmitterType -ucl_emit_msgpack = 4 :: UCLEmitterType - -ucl_parser_parse_string_pure :: String -> Either UCLObjectHandle ErrorString -ucl_parser_parse_string_pure s = unsafePerformIO $ do - cs <- newCString s - let p = ucl_parser_new 0x4 - didParse <- ucl_parser_add_string p cs (toEnum $ length s) - if didParse - then return $ Left $ ucl_parser_get_object p - else Right <$> peekCString ( ucl_parser_get_error p) - -ucl_parser_add_file_pure :: String -> Either UCLObjectHandle ErrorString -ucl_parser_add_file_pure s = unsafePerformIO $ do - cs <- newCString s - let p = ucl_parser_new 0x4 - didParse <- ucl_parser_add_file p cs - if didParse - then return $ Left $ ucl_parser_get_object p - else Right <$> peekCString ( ucl_parser_get_error p) - -unpack :: MSG.MessagePack a => String -> Either a ErrorString -unpack s = case ucl_parser_parse_string_pure s of - (Right err) -> Right err - (Left obj) -> case MSG.fromObject (ucl_to_msgpack_object obj) of - Nothing -> Right "MessagePack fromObject Error" - (Just a) -> Left a - -ucl_to_msgpack_object :: UCLObjectHandle -> MSG.Object -ucl_to_msgpack_object o = toMsgPackObj (ucl_object_type o) o - where - toMsgPackObj n obj - |n==ucl_OBJECT = MSG.ObjectMap $ uclObjectToVector obj - |n==ucl_ARRAY = MSG.ObjectArray undefined - |n==ucl_INT = MSG.ObjectInt $ fromEnum $ ucl_object_toint obj - |n==ucl_FLOAT = MSG.ObjectDouble $ realToFrac $ ucl_object_todouble obj - |n==ucl_STRING = MSG.ObjectStr $ T.pack $ unsafePerformIO $ peekCString $ ucl_object_tostring obj - |n==ucl_BOOLEAN = MSG.ObjectBool $ ucl_object_toboolean obj - |n==ucl_TIME = error "time undefined" - |n==ucl_USERDATA = error "userdata undefined" - |n==ucl_NULL = error "null undefined" - |otherwise = error "\"Unknown Type\" Error" - -uclObjectToVector :: UCLObjectHandle -> V.Vector (MSG.Object,MSG.Object) -uclObjectToVector o = iterateObject (ucl_object_iterate_safe iter True ) iter V.empty - where - iter = ucl_object_iterate_new o - iterateObject obj it vec = if ucl_object_type obj == ucl_NULL - then vec - else iterateObject (ucl_object_iterate_safe it True) it (V.snoc vec ( getUclKey obj , ucl_to_msgpack_object obj)) - getUclKey obj = MSG.ObjectStr $ T.pack $ unsafePerformIO $ peekCString $ ucl_object_key obj - -uclArrayToVector :: UCLObjectHandle -> V.Vector MSG.Object -uclArrayToVector o = iterateArray (ucl_object_iterate_safe iter True ) iter V.empty - where - iter = ucl_object_iterate_new o - iterateArray obj it vec = if ucl_object_type obj == ucl_NULL - then vec - else iterateArray (ucl_object_iterate_safe it True) it (V.snoc vec (ucl_to_msgpack_object obj)) - diff --git a/contrib/libucl/include/ucl.h b/contrib/libucl/include/ucl.h index 39da2593648d..b8625b9fce2f 100644 --- a/contrib/libucl/include/ucl.h +++ b/contrib/libucl/include/ucl.h @@ -1411,13 +1411,13 @@ struct ucl_emitter_operations { const ucl_object_t *obj, bool first, bool print_key); /** Start ucl object */ void (*ucl_emitter_start_object) (struct ucl_emitter_context *ctx, - const ucl_object_t *obj, bool print_key); + const ucl_object_t *obj, bool first, bool print_key); /** End ucl object */ void (*ucl_emitter_end_object) (struct ucl_emitter_context *ctx, const ucl_object_t *obj); /** Start ucl array */ void (*ucl_emitter_start_array) (struct ucl_emitter_context *ctx, - const ucl_object_t *obj, bool print_key); + const ucl_object_t *obj, bool first, bool print_key); void (*ucl_emitter_end_array) (struct ucl_emitter_context *ctx, const ucl_object_t *obj); }; diff --git a/contrib/libucl/libucl.pc b/contrib/libucl/libucl.pc deleted file mode 100644 index 4878bebafcdd..000000000000 --- a/contrib/libucl/libucl.pc +++ /dev/null @@ -1,11 +0,0 @@ -prefix=/usr/local -exec_prefix=${prefix} -libdir=${exec_prefix}/lib -includedir=${prefix}/include - -Name: LibUCL -Description: Universal configuration library -Version: 0.9.0 -Libs: -L${libdir} -lucl -Libs.private: -Cflags: -I${includedir}/ diff --git a/contrib/libucl/libucl.pc.in b/contrib/libucl/libucl.pc.in deleted file mode 100644 index 3433fa9d8b1c..000000000000 --- a/contrib/libucl/libucl.pc.in +++ /dev/null @@ -1,11 +0,0 @@ -prefix=@prefix@ -exec_prefix=@exec_prefix@ -libdir=@libdir@ -includedir=@includedir@ - -Name: LibUCL -Description: Universal configuration library -Version: @UCL_VERSION@ -Libs: -L${libdir} -lucl -Libs.private: @LIBS_EXTRA@ @LUA_LIB@ -Cflags: -I${includedir}/ diff --git a/contrib/libucl/lua/Makefile.am b/contrib/libucl/lua/Makefile.am deleted file mode 100644 index 95beafbfc94e..000000000000 --- a/contrib/libucl/lua/Makefile.am +++ /dev/null @@ -1,26 +0,0 @@ -ucl_common_cflags= -I$(top_srcdir)/src \ - -I$(top_srcdir)/include \ - -I$(top_srcdir)/uthash \ - -Wall -W -Wno-unused-parameter -Wno-pointer-sign -luaexec_LTLIBRARIES= ucl.la -ucl_la_SOURCES= lua_ucl.c -ucl_la_CFLAGS= $(ucl_common_cflags) \ - @LUA_INCLUDE@ -ucl_la_LDFLAGS = -module -export-dynamic -avoid-version -ucl_la_LIBADD= $(top_srcdir)/src/libucl.la \ - @LIBFETCH_LIBS@ \ - @LIBCRYPTO_LIB@ \ - @LIBREGEX_LIB@ \ - @CURL_LIBS@ \ - @LUA_LIB@ - -include_HEADERS= $(top_srcdir)/include/lua_ucl.h - -ROCKSPEC = $(PACKAGE)-$(VERSION)-1.rockspec -EXTRA_DIST = $(PACKAGE).rockspec.in \ - test.lua -DISTCLEANFILES = $(PACKAGE).rockspec - -$(ROCKSPEC): $(PACKAGE).rockspec dist - sed -e 's/@MD5@/'`$(MD5SUM) $(distdir).tar.gz | \ - cut -d " " -f 1`'/g' < $(PACKAGE).rockspec > $@
\ No newline at end of file diff --git a/contrib/libucl/lua/libucl.rockspec.in b/contrib/libucl/lua/libucl.rockspec.in deleted file mode 100644 index 52f39176a7bd..000000000000 --- a/contrib/libucl/lua/libucl.rockspec.in +++ /dev/null @@ -1,26 +0,0 @@ -package="@PACKAGE@" -version="@VERSION@-1" -source = { - url = "https://github.com/downloads/vstakhov/@PACKAGE@/@PACKAGE@-@VERSION@.tar.gz", - md5 = "@MD5@", - dir = "@PACKAGE@-@VERSION@" -} -description = { - summary = "UCL - json like configuration language", - detailed = [[ - UCL is heavily infused by nginx configuration as the example - of a convenient configuration system. - However, UCL is fully compatible with JSON format and is able - to parse json files. - ]], - homepage = "http://github.com/vstakhov/@PACKAGE@/", - license = "" -} -dependencies = { - "lua >= 5.1" -} -build = { - type = "command", - build_command = "LUA=$(LUA) CPPFLAGS=-I$(LUA_INCDIR) ./configure --prefix=$(PREFIX) --libdir=$(LIBDIR) --datadir=$(LUADIR) && make clean && make", - install_command = "make install" -} diff --git a/contrib/libucl/lua/lua_ucl.c b/contrib/libucl/lua/lua_ucl.c index b34fd56878b8..d6be69e42a71 100644 --- a/contrib/libucl/lua/lua_ucl.c +++ b/contrib/libucl/lua/lua_ucl.c @@ -82,6 +82,11 @@ static ucl_object_t* ucl_object_lua_fromelt (lua_State *L, int idx, ucl_string_f static void *ucl_null; +struct _rspamd_lua_text { + const char *start; + unsigned int len; + unsigned int flags; +}; enum lua_ucl_push_flags { LUA_UCL_DEFAULT_FLAGS = 0, @@ -240,7 +245,7 @@ ucl_object_lua_push_scalar (lua_State *L, const ucl_object_t *obj, lua_pushboolean (L, ucl_obj_toboolean (obj)); break; case UCL_STRING: - lua_pushstring (L, ucl_obj_tostring (obj)); + lua_pushlstring (L, ucl_obj_tostring (obj), obj->len); break; case UCL_INT: #if LUA_VERSION_NUM >= 501 @@ -401,7 +406,6 @@ ucl_object_lua_fromtable (lua_State *L, int idx, ucl_string_flags_t flags) /* Table iterate */ if (is_array) { - int i; if (!is_implicit) { top = ucl_object_typed_new (UCL_ARRAY); @@ -411,7 +415,7 @@ ucl_object_lua_fromtable (lua_State *L, int idx, ucl_string_flags_t flags) top = NULL; } - for (i = 1; i <= max; i ++) { + for (size_t i = 1; i <= max; i ++) { lua_pushinteger (L, i); lua_gettable (L, idx); @@ -479,7 +483,16 @@ ucl_object_lua_fromelt (lua_State *L, int idx, ucl_string_flags_t flags) str = lua_tolstring (L, idx, &sz); if (str) { - obj = ucl_object_fromstring_common (str, sz, flags); + /* + * ucl_object_fromstring_common has a `logic` to use strlen if sz is zero + * which is totally broken... + */ + if (sz > 0) { + obj = ucl_object_fromstring_common(str, sz, flags); + } + else { + obj = ucl_object_fromstring_common("", sz, flags); + } } else { obj = ucl_object_typed_new (UCL_NULL); @@ -501,6 +514,24 @@ ucl_object_lua_fromelt (lua_State *L, int idx, ucl_string_flags_t flags) if (lua_topointer (L, idx) == ucl_null) { obj = ucl_object_typed_new (UCL_NULL); } + else { + /* Assume it is a text like object */ + struct _rspamd_lua_text *t = lua_touserdata (L, idx); + + if (t) { + if (t->len >0) { + obj = ucl_object_fromstring_common(t->start, t->len, 0); + } + else { + obj = ucl_object_fromstring_common("", 0, 0); + } + + /* Binary text */ + if (t->flags & (1u << 5u)) { + obj->flags |= UCL_OBJECT_BINARY; + } + } + } break; case LUA_TTABLE: case LUA_TFUNCTION: @@ -556,10 +587,10 @@ ucl_object_lua_import (lua_State *L, int idx) t = lua_type (L, idx); switch (t) { case LUA_TTABLE: - obj = ucl_object_lua_fromtable (L, idx, 0); + obj = ucl_object_lua_fromtable (L, idx, UCL_STRING_RAW); break; default: - obj = ucl_object_lua_fromelt (L, idx, 0); + obj = ucl_object_lua_fromelt (L, idx, UCL_STRING_RAW); break; } @@ -584,10 +615,10 @@ ucl_object_lua_import_escape (lua_State *L, int idx) t = lua_type (L, idx); switch (t) { case LUA_TTABLE: - obj = ucl_object_lua_fromtable (L, idx, UCL_STRING_RAW); + obj = ucl_object_lua_fromtable (L, idx, UCL_STRING_ESCAPE); break; default: - obj = ucl_object_lua_fromelt (L, idx, UCL_STRING_RAW); + obj = ucl_object_lua_fromelt (L, idx, UCL_STRING_ESCAPE); break; } @@ -598,11 +629,12 @@ static int lua_ucl_to_string (lua_State *L, const ucl_object_t *obj, enum ucl_emitter type) { unsigned char *result; + size_t outlen; - result = ucl_object_emit (obj, type); + result = ucl_object_emit_len (obj, type, &outlen); if (result != NULL) { - lua_pushstring (L, (const char *)result); + lua_pushlstring (L, (const char *)result, outlen); free (result); } else { @@ -625,7 +657,6 @@ lua_ucl_parser_init (lua_State *L) parser = ucl_parser_new (flags); if (parser == NULL) { lua_pushnil (L); - return 1; } pparser = lua_newuserdata (L, sizeof (parser)); @@ -834,12 +865,6 @@ lua_ucl_parser_parse_string (lua_State *L) return ret; } -struct _rspamd_lua_text { - const char *start; - unsigned int len; - unsigned int flags; -}; - /*** * @method parser:parse_text(input) * Parse UCL object from text object (Rspamd specific). @@ -855,7 +880,24 @@ lua_ucl_parser_parse_text (lua_State *L) int ret = 2; parser = lua_ucl_parser_get (L, 1); - t = lua_touserdata (L, 2); + + if (lua_type (L, 2) == LUA_TUSERDATA) { + t = lua_touserdata (L, 2); + } + else if (lua_type (L, 2) == LUA_TSTRING) { + const char *s; + size_t len; + static struct _rspamd_lua_text st_t; + + s = lua_tolstring (L, 2, &len); + st_t.start = s; + st_t.len = len; + + t = &st_t; + } + else { + return luaL_error(L, "invalid argument as input, expected userdata or a string"); + } if (lua_type (L, 3) == LUA_TSTRING) { type = lua_ucl_str_to_parse_type (lua_tostring (L, 3)); @@ -1426,10 +1468,11 @@ lua_ucl_to_format (lua_State *L) format = UCL_EMIT_YAML; } else if (strcasecmp (strtype, "config") == 0 || - strcasecmp (strtype, "ucl") == 0) { + strcasecmp (strtype, "ucl") == 0) { format = UCL_EMIT_CONFIG; } - else if (strcasecmp (strtype, "msgpack") == 0) { + else if (strcasecmp (strtype, "msgpack") == 0 || + strcasecmp (strtype, "messagepack") == 0) { format = UCL_EMIT_MSGPACK; } } diff --git a/contrib/libucl/m4/ax_lua.m4 b/contrib/libucl/m4/ax_lua.m4 deleted file mode 100644 index f8e2fd4c85ce..000000000000 --- a/contrib/libucl/m4/ax_lua.m4 +++ /dev/null @@ -1,664 +0,0 @@ -# =========================================================================== -# http://www.gnu.org/software/autoconf-archive/ax_lua.html -# =========================================================================== -# -# SYNOPSIS -# -# AX_PROG_LUA[([MINIMUM-VERSION], [TOO-BIG-VERSION], [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])] -# AX_LUA_HEADERS[([ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])] -# AX_LUA_LIBS[([ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])] -# AX_LUA_READLINE[([ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])] -# -# DESCRIPTION -# -# Detect a Lua interpreter, optionally specifying a minimum and maximum -# version number. Set up important Lua paths, such as the directories in -# which to install scripts and modules (shared libraries). -# -# Also detect Lua headers and libraries. The Lua version contained in the -# header is checked to match the Lua interpreter version exactly. When -# searching for Lua libraries, the version number is used as a suffix. -# This is done with the goal of supporting multiple Lua installs (5.1, -# 5.2, and 5.3 side-by-side). -# -# A note on compatibility with previous versions: This file has been -# mostly rewritten for serial 18. Most developers should be able to use -# these macros without needing to modify configure.ac. Care has been taken -# to preserve each macro's behavior, but there are some differences: -# -# 1) AX_WITH_LUA is deprecated; it now expands to the exact same thing as -# AX_PROG_LUA with no arguments. -# -# 2) AX_LUA_HEADERS now checks that the version number defined in lua.h -# matches the interpreter version. AX_LUA_HEADERS_VERSION is therefore -# unnecessary, so it is deprecated and does not expand to anything. -# -# 3) The configure flag --with-lua-suffix no longer exists; the user -# should instead specify the LUA precious variable on the command line. -# See the AX_PROG_LUA description for details. -# -# Please read the macro descriptions below for more information. -# -# This file was inspired by Andrew Dalke's and James Henstridge's -# python.m4 and Tom Payne's, Matthieu Moy's, and Reuben Thomas's ax_lua.m4 -# (serial 17). Basically, this file is a mash-up of those two files. I -# like to think it combines the best of the two! -# -# AX_PROG_LUA: Search for the Lua interpreter, and set up important Lua -# paths. Adds precious variable LUA, which may contain the path of the Lua -# interpreter. If LUA is blank, the user's path is searched for an -# suitable interpreter. -# -# If MINIMUM-VERSION is supplied, then only Lua interpreters with a -# version number greater or equal to MINIMUM-VERSION will be accepted. If -# TOO-BIG-VERSION is also supplied, then only Lua interpreters with a -# version number greater or equal to MINIMUM-VERSION and less than -# TOO-BIG-VERSION will be accepted. -# -# The Lua version number, LUA_VERSION, is found from the interpreter, and -# substituted. LUA_PLATFORM is also found, but not currently supported (no -# standard representation). -# -# Finally, the macro finds four paths: -# -# luadir Directory to install Lua scripts. -# pkgluadir $luadir/$PACKAGE -# luaexecdir Directory to install Lua modules. -# pkgluaexecdir $luaexecdir/$PACKAGE -# -# These paths are found based on $prefix, $exec_prefix, Lua's -# package.path, and package.cpath. The first path of package.path -# beginning with $prefix is selected as luadir. The first path of -# package.cpath beginning with $exec_prefix is used as luaexecdir. This -# should work on all reasonable Lua installations. If a path cannot be -# determined, a default path is used. Of course, the user can override -# these later when invoking make. -# -# luadir Default: $prefix/share/lua/$LUA_VERSION -# luaexecdir Default: $exec_prefix/lib/lua/$LUA_VERSION -# -# These directories can be used by Automake as install destinations. The -# variable name minus 'dir' needs to be used as a prefix to the -# appropriate Automake primary, e.g. lua_SCRIPS or luaexec_LIBRARIES. -# -# If an acceptable Lua interpreter is found, then ACTION-IF-FOUND is -# performed, otherwise ACTION-IF-NOT-FOUND is preformed. If ACTION-IF-NOT- -# FOUND is blank, then it will default to printing an error. To prevent -# the default behavior, give ':' as an action. -# -# AX_LUA_HEADERS: Search for Lua headers. Requires that AX_PROG_LUA be -# expanded before this macro. Adds precious variable LUA_INCLUDE, which -# may contain Lua specific include flags, e.g. -I/usr/include/lua5.1. If -# LUA_INCLUDE is blank, then this macro will attempt to find suitable -# flags. -# -# LUA_INCLUDE can be used by Automake to compile Lua modules or -# executables with embedded interpreters. The *_CPPFLAGS variables should -# be used for this purpose, e.g. myprog_CPPFLAGS = $(LUA_INCLUDE). -# -# This macro searches for the header lua.h (and others). The search is -# performed with a combination of CPPFLAGS, CPATH, etc, and LUA_INCLUDE. -# If the search is unsuccessful, then some common directories are tried. -# If the headers are then found, then LUA_INCLUDE is set accordingly. -# -# The paths automatically searched are: -# -# * /usr/include/luaX.Y -# * /usr/include/lua/X.Y -# * /usr/include/luaXY -# * /usr/local/include/luaX.Y -# * /usr/local/include/lua-X.Y -# * /usr/local/include/lua/X.Y -# * /usr/local/include/luaXY -# -# (Where X.Y is the Lua version number, e.g. 5.1.) -# -# The Lua version number found in the headers is always checked to match -# the Lua interpreter's version number. Lua headers with mismatched -# version numbers are not accepted. -# -# If headers are found, then ACTION-IF-FOUND is performed, otherwise -# ACTION-IF-NOT-FOUND is performed. If ACTION-IF-NOT-FOUND is blank, then -# it will default to printing an error. To prevent the default behavior, -# set the action to ':'. -# -# AX_LUA_LIBS: Search for Lua libraries. Requires that AX_PROG_LUA be -# expanded before this macro. Adds precious variable LUA_LIB, which may -# contain Lua specific linker flags, e.g. -llua5.1. If LUA_LIB is blank, -# then this macro will attempt to find suitable flags. -# -# LUA_LIB can be used by Automake to link Lua modules or executables with -# embedded interpreters. The *_LIBADD and *_LDADD variables should be used -# for this purpose, e.g. mymod_LIBADD = $(LUA_LIB). -# -# This macro searches for the Lua library. More technically, it searches -# for a library containing the function lua_load. The search is performed -# with a combination of LIBS, LIBRARY_PATH, and LUA_LIB. -# -# If the search determines that some linker flags are missing, then those -# flags will be added to LUA_LIB. -# -# If libraries are found, then ACTION-IF-FOUND is performed, otherwise -# ACTION-IF-NOT-FOUND is performed. If ACTION-IF-NOT-FOUND is blank, then -# it will default to printing an error. To prevent the default behavior, -# set the action to ':'. -# -# AX_LUA_READLINE: Search for readline headers and libraries. Requires the -# AX_LIB_READLINE macro, which is provided by ax_lib_readline.m4 from the -# Autoconf Archive. -# -# If a readline compatible library is found, then ACTION-IF-FOUND is -# performed, otherwise ACTION-IF-NOT-FOUND is performed. -# -# LICENSE -# -# Copyright (c) 2015 Reuben Thomas <rrt@sc3d.org> -# Copyright (c) 2014 Tim Perkins <tprk77@gmail.com> -# -# This program is free software: you can redistribute it and/or modify it -# under the terms of the GNU General Public License as published by the -# Free Software Foundation, either version 3 of the License, or (at your -# option) any later version. -# -# This program is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General -# Public License for more details. -# -# You should have received a copy of the GNU General Public License along -# with this program. If not, see <http://www.gnu.org/licenses/>. -# -# As a special exception, the respective Autoconf Macro's copyright owner -# gives unlimited permission to copy, distribute and modify the configure -# scripts that are the output of Autoconf when processing the Macro. You -# need not follow the terms of the GNU General Public License when using -# or distributing such scripts, even though portions of the text of the -# Macro appear in them. The GNU General Public License (GPL) does govern -# all other use of the material that constitutes the Autoconf Macro. -# -# This special exception to the GPL applies to versions of the Autoconf -# Macro released by the Autoconf Archive. When you make and distribute a -# modified version of the Autoconf Macro, you may extend this special -# exception to the GPL to apply to your modified version as well. - -#serial 39 - -dnl ========================================================================= -dnl AX_PROG_LUA([MINIMUM-VERSION], [TOO-BIG-VERSION], -dnl [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND]) -dnl ========================================================================= -AC_DEFUN([AX_PROG_LUA], -[ - dnl Check for required tools. - AC_REQUIRE([AC_PROG_GREP]) - AC_REQUIRE([AC_PROG_SED]) - - dnl Make LUA a precious variable. - AC_ARG_VAR([LUA], [The Lua interpreter, e.g. /usr/bin/lua5.1]) - - dnl Find a Lua interpreter. - m4_define_default([_AX_LUA_INTERPRETER_LIST], - [lua lua5.3 lua53 lua5.2 lua52 lua5.1 lua51 lua50]) - - m4_if([$1], [], - [ dnl No version check is needed. Find any Lua interpreter. - AS_IF([test "x$LUA" = 'x'], - [AC_PATH_PROGS([LUA], [_AX_LUA_INTERPRETER_LIST], [:])]) - ax_display_LUA='lua' - - AS_IF([test "x$LUA" != 'x:'], - [ dnl At least check if this is a Lua interpreter. - AC_MSG_CHECKING([if $LUA is a Lua interpreter]) - _AX_LUA_CHK_IS_INTRP([$LUA], - [AC_MSG_RESULT([yes])], - [ AC_MSG_RESULT([no]) - AC_MSG_ERROR([not a Lua interpreter]) - ]) - ]) - ], - [ dnl A version check is needed. - AS_IF([test "x$LUA" != 'x'], - [ dnl Check if this is a Lua interpreter. - AC_MSG_CHECKING([if $LUA is a Lua interpreter]) - _AX_LUA_CHK_IS_INTRP([$LUA], - [AC_MSG_RESULT([yes])], - [ AC_MSG_RESULT([no]) - AC_MSG_ERROR([not a Lua interpreter]) - ]) - dnl Check the version. - m4_if([$2], [], - [_ax_check_text="whether $LUA version >= $1"], - [_ax_check_text="whether $LUA version >= $1, < $2"]) - AC_MSG_CHECKING([$_ax_check_text]) - _AX_LUA_CHK_VER([$LUA], [$1], [$2], - [AC_MSG_RESULT([yes])], - [ AC_MSG_RESULT([no]) - AC_MSG_ERROR([version is out of range for specified LUA])]) - ax_display_LUA=$LUA - ], - [ dnl Try each interpreter until we find one that satisfies VERSION. - m4_if([$2], [], - [_ax_check_text="for a Lua interpreter with version >= $1"], - [_ax_check_text="for a Lua interpreter with version >= $1, < $2"]) - AC_CACHE_CHECK([$_ax_check_text], - [ax_cv_pathless_LUA], - [ for ax_cv_pathless_LUA in _AX_LUA_INTERPRETER_LIST none; do - test "x$ax_cv_pathless_LUA" = 'xnone' && break - _AX_LUA_CHK_IS_INTRP([$ax_cv_pathless_LUA], [], [continue]) - _AX_LUA_CHK_VER([$ax_cv_pathless_LUA], [$1], [$2], [break]) - done - ]) - dnl Set $LUA to the absolute path of $ax_cv_pathless_LUA. - AS_IF([test "x$ax_cv_pathless_LUA" = 'xnone'], - [LUA=':'], - [AC_PATH_PROG([LUA], [$ax_cv_pathless_LUA])]) - ax_display_LUA=$ax_cv_pathless_LUA - ]) - ]) - - AS_IF([test "x$LUA" = 'x:'], - [ dnl Run any user-specified action, or abort. - m4_default([$4], [AC_MSG_ERROR([cannot find suitable Lua interpreter])]) - ], - [ dnl Query Lua for its version number. - AC_CACHE_CHECK([for $ax_display_LUA version], - [ax_cv_lua_version], - [ dnl Get the interpreter version in X.Y format. This should work for - dnl interpreters version 5.0 and beyond. - ax_cv_lua_version=[`$LUA -e ' - -- return a version number in X.Y format - local _, _, ver = string.find(_VERSION, "^Lua (%d+%.%d+)") - print(ver)'`] - ]) - AS_IF([test "x$ax_cv_lua_version" = 'x'], - [AC_MSG_ERROR([invalid Lua version number])]) - AC_SUBST([LUA_VERSION], [$ax_cv_lua_version]) - AC_SUBST([LUA_SHORT_VERSION], [`echo "$LUA_VERSION" | $SED 's|\.||'`]) - - dnl The following check is not supported: - dnl At times (like when building shared libraries) you may want to know - dnl which OS platform Lua thinks this is. - AC_CACHE_CHECK([for $ax_display_LUA platform], - [ax_cv_lua_platform], - [ax_cv_lua_platform=[`$LUA -e 'print("unknown")'`]]) - AC_SUBST([LUA_PLATFORM], [$ax_cv_lua_platform]) - - dnl Use the values of $prefix and $exec_prefix for the corresponding - dnl values of LUA_PREFIX and LUA_EXEC_PREFIX. These are made distinct - dnl variables so they can be overridden if need be. However, the general - dnl consensus is that you shouldn't need this ability. - AC_SUBST([LUA_PREFIX], ['${prefix}']) - AC_SUBST([LUA_EXEC_PREFIX], ['${exec_prefix}']) - - dnl Lua provides no way to query the script directory, and instead - dnl provides LUA_PATH. However, we should be able to make a safe educated - dnl guess. If the built-in search path contains a directory which is - dnl prefixed by $prefix, then we can store scripts there. The first - dnl matching path will be used. - AC_CACHE_CHECK([for $ax_display_LUA script directory], - [ax_cv_lua_luadir], - [ AS_IF([test "x$prefix" = 'xNONE'], - [ax_lua_prefix=$ac_default_prefix], - [ax_lua_prefix=$prefix]) - - dnl Initialize to the default path. - ax_cv_lua_luadir="$LUA_PREFIX/share/lua/$LUA_VERSION" - - dnl Try to find a path with the prefix. - _AX_LUA_FND_PRFX_PTH([$LUA], [$ax_lua_prefix], [script]) - AS_IF([test "x$ax_lua_prefixed_path" != 'x'], - [ dnl Fix the prefix. - _ax_strip_prefix=`echo "$ax_lua_prefix" | $SED 's|.|.|g'` - ax_cv_lua_luadir=`echo "$ax_lua_prefixed_path" | \ - $SED "s|^$_ax_strip_prefix|$LUA_PREFIX|"` - ]) - ]) - AC_SUBST([luadir], [$ax_cv_lua_luadir]) - AC_SUBST([pkgluadir], [\${luadir}/$PACKAGE]) - - dnl Lua provides no way to query the module directory, and instead - dnl provides LUA_PATH. However, we should be able to make a safe educated - dnl guess. If the built-in search path contains a directory which is - dnl prefixed by $exec_prefix, then we can store modules there. The first - dnl matching path will be used. - AC_CACHE_CHECK([for $ax_display_LUA module directory], - [ax_cv_lua_luaexecdir], - [ AS_IF([test "x$exec_prefix" = 'xNONE'], - [ax_lua_exec_prefix=$ax_lua_prefix], - [ax_lua_exec_prefix=$exec_prefix]) - - dnl Initialize to the default path. - ax_cv_lua_luaexecdir="$LUA_EXEC_PREFIX/lib/lua/$LUA_VERSION" - - dnl Try to find a path with the prefix. - _AX_LUA_FND_PRFX_PTH([$LUA], - [$ax_lua_exec_prefix], [module]) - AS_IF([test "x$ax_lua_prefixed_path" != 'x'], - [ dnl Fix the prefix. - _ax_strip_prefix=`echo "$ax_lua_exec_prefix" | $SED 's|.|.|g'` - ax_cv_lua_luaexecdir=`echo "$ax_lua_prefixed_path" | \ - $SED "s|^$_ax_strip_prefix|$LUA_EXEC_PREFIX|"` - ]) - ]) - AC_SUBST([luaexecdir], [$ax_cv_lua_luaexecdir]) - AC_SUBST([pkgluaexecdir], [\${luaexecdir}/$PACKAGE]) - - dnl Run any user specified action. - $3 - ]) -]) - -dnl AX_WITH_LUA is now the same thing as AX_PROG_LUA. -AC_DEFUN([AX_WITH_LUA], -[ - AC_MSG_WARN([[$0 is deprecated, please use AX_PROG_LUA instead]]) - AX_PROG_LUA -]) - - -dnl ========================================================================= -dnl _AX_LUA_CHK_IS_INTRP(PROG, [ACTION-IF-TRUE], [ACTION-IF-FALSE]) -dnl ========================================================================= -AC_DEFUN([_AX_LUA_CHK_IS_INTRP], -[ - dnl A minimal Lua factorial to prove this is an interpreter. This should work - dnl for Lua interpreters version 5.0 and beyond. - _ax_lua_factorial=[`$1 2>/dev/null -e ' - -- a simple factorial - function fact (n) - if n == 0 then - return 1 - else - return n * fact(n-1) - end - end - print("fact(5) is " .. fact(5))'`] - AS_IF([test "$_ax_lua_factorial" = 'fact(5) is 120'], - [$2], [$3]) -]) - - -dnl ========================================================================= -dnl _AX_LUA_CHK_VER(PROG, MINIMUM-VERSION, [TOO-BIG-VERSION], -dnl [ACTION-IF-TRUE], [ACTION-IF-FALSE]) -dnl ========================================================================= -AC_DEFUN([_AX_LUA_CHK_VER], -[ - dnl Check that the Lua version is within the bounds. Only the major and minor - dnl version numbers are considered. This should work for Lua interpreters - dnl version 5.0 and beyond. - _ax_lua_good_version=[`$1 -e ' - -- a script to compare versions - function verstr2num(verstr) - local _, _, majorver, minorver = string.find(verstr, "^(%d+)%.(%d+)") - if majorver and minorver then - return tonumber(majorver) * 100 + tonumber(minorver) - end - end - local minver = verstr2num("$2") - local _, _, trimver = string.find(_VERSION, "^Lua (.*)") - local ver = verstr2num(trimver) - local maxver = verstr2num("$3") or 1e9 - if minver <= ver and ver < maxver then - print("yes") - else - print("no") - end'`] - AS_IF([test "x$_ax_lua_good_version" = "xyes"], - [$4], [$5]) -]) - - -dnl ========================================================================= -dnl _AX_LUA_FND_PRFX_PTH(PROG, PREFIX, SCRIPT-OR-MODULE-DIR) -dnl ========================================================================= -AC_DEFUN([_AX_LUA_FND_PRFX_PTH], -[ - dnl Get the script or module directory by querying the Lua interpreter, - dnl filtering on the given prefix, and selecting the shallowest path. If no - dnl path is found matching the prefix, the result will be an empty string. - dnl The third argument determines the type of search, it can be 'script' or - dnl 'module'. Supplying 'script' will perform the search with package.path - dnl and LUA_PATH, and supplying 'module' will search with package.cpath and - dnl LUA_CPATH. This is done for compatibility with Lua 5.0. - - ax_lua_prefixed_path=[`$1 -e ' - -- get the path based on search type - local searchtype = "$3" - local paths = "" - if searchtype == "script" then - paths = (package and package.path) or LUA_PATH - elseif searchtype == "module" then - paths = (package and package.cpath) or LUA_CPATH - end - -- search for the prefix - local prefix = "'$2'" - local minpath = "" - local mindepth = 1e9 - string.gsub(paths, "(@<:@^;@:>@+)", - function (path) - path = string.gsub(path, "%?.*$", "") - path = string.gsub(path, "/@<:@^/@:>@*$", "") - if string.find(path, prefix) then - local depth = string.len(string.gsub(path, "@<:@^/@:>@", "")) - if depth < mindepth then - minpath = path - mindepth = depth - end - end - end) - print(minpath)'`] -]) - - -dnl ========================================================================= -dnl AX_LUA_HEADERS([ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND]) -dnl ========================================================================= -AC_DEFUN([AX_LUA_HEADERS], -[ - dnl Check for LUA_VERSION. - AC_MSG_CHECKING([if LUA_VERSION is defined]) - AS_IF([test "x$LUA_VERSION" != 'x'], - [AC_MSG_RESULT([yes])], - [ AC_MSG_RESULT([no]) - AC_MSG_ERROR([cannot check Lua headers without knowing LUA_VERSION]) - ]) - - dnl Make LUA_INCLUDE a precious variable. - AC_ARG_VAR([LUA_INCLUDE], [The Lua includes, e.g. -I/usr/include/lua5.1]) - - dnl Some default directories to search. - LUA_SHORT_VERSION=`echo "$LUA_VERSION" | $SED 's|\.||'` - m4_define_default([_AX_LUA_INCLUDE_LIST], - [ /usr/include/lua$LUA_VERSION \ - /usr/include/lua-$LUA_VERSION \ - /usr/include/lua/$LUA_VERSION \ - /usr/include/lua$LUA_SHORT_VERSION \ - /usr/local/include/lua$LUA_VERSION \ - /usr/local/include/lua-$LUA_VERSION \ - /usr/local/include/lua/$LUA_VERSION \ - /usr/local/include/lua$LUA_SHORT_VERSION \ - ]) - - dnl Try to find the headers. - _ax_lua_saved_cppflags=$CPPFLAGS - CPPFLAGS="$CPPFLAGS $LUA_INCLUDE" - AC_CHECK_HEADERS([lua.h lualib.h lauxlib.h luaconf.h]) - CPPFLAGS=$_ax_lua_saved_cppflags - - dnl Try some other directories if LUA_INCLUDE was not set. - AS_IF([test "x$LUA_INCLUDE" = 'x' && - test "x$ac_cv_header_lua_h" != 'xyes'], - [ dnl Try some common include paths. - for _ax_include_path in _AX_LUA_INCLUDE_LIST; do - test ! -d "$_ax_include_path" && continue - - AC_MSG_CHECKING([for Lua headers in]) - AC_MSG_RESULT([$_ax_include_path]) - - AS_UNSET([ac_cv_header_lua_h]) - AS_UNSET([ac_cv_header_lualib_h]) - AS_UNSET([ac_cv_header_lauxlib_h]) - AS_UNSET([ac_cv_header_luaconf_h]) - - _ax_lua_saved_cppflags=$CPPFLAGS - CPPFLAGS="$CPPFLAGS -I$_ax_include_path" - AC_CHECK_HEADERS([lua.h lualib.h lauxlib.h luaconf.h]) - CPPFLAGS=$_ax_lua_saved_cppflags - - AS_IF([test "x$ac_cv_header_lua_h" = 'xyes'], - [ LUA_INCLUDE="-I$_ax_include_path" - break - ]) - done - ]) - - AS_IF([test "x$ac_cv_header_lua_h" = 'xyes'], - [ dnl Make a program to print LUA_VERSION defined in the header. - dnl TODO It would be really nice if we could do this without compiling a - dnl program, then it would work when cross compiling. But I'm not sure how - dnl to do this reliably. For now, assume versions match when cross compiling. - - AS_IF([test "x$cross_compiling" != 'xyes'], - [ AC_CACHE_CHECK([for Lua header version], - [ax_cv_lua_header_version], - [ _ax_lua_saved_cppflags=$CPPFLAGS - CPPFLAGS="$CPPFLAGS $LUA_INCLUDE" - AC_RUN_IFELSE( - [ AC_LANG_SOURCE([[ -#include <lua.h> -#include <stdlib.h> -#include <stdio.h> -int main(int argc, char ** argv) -{ - if(argc > 1) printf("%s", LUA_VERSION); - exit(EXIT_SUCCESS); -} -]]) - ], - [ ax_cv_lua_header_version=`./conftest$EXEEXT p | \ - $SED -n "s|^Lua \(@<:@0-9@:>@\{1,\}\.@<:@0-9@:>@\{1,\}\).\{0,\}|\1|p"` - ], - [ax_cv_lua_header_version='unknown']) - CPPFLAGS=$_ax_lua_saved_cppflags - ]) - - dnl Compare this to the previously found LUA_VERSION. - AC_MSG_CHECKING([if Lua header version matches $LUA_VERSION]) - AS_IF([test "x$ax_cv_lua_header_version" = "x$LUA_VERSION"], - [ AC_MSG_RESULT([yes]) - ax_header_version_match='yes' - ], - [ AC_MSG_RESULT([no]) - ax_header_version_match='no' - ]) - ], - [ AC_MSG_WARN([cross compiling so assuming header version number matches]) - ax_header_version_match='yes' - ]) - ]) - - dnl Was LUA_INCLUDE specified? - AS_IF([test "x$ax_header_version_match" != 'xyes' && - test "x$LUA_INCLUDE" != 'x'], - [AC_MSG_ERROR([cannot find headers for specified LUA_INCLUDE])]) - - dnl Test the final result and run user code. - AS_IF([test "x$ax_header_version_match" = 'xyes'], [$1], - [m4_default([$2], [AC_MSG_ERROR([cannot find Lua includes])])]) -]) - -dnl AX_LUA_HEADERS_VERSION no longer exists, use AX_LUA_HEADERS. -AC_DEFUN([AX_LUA_HEADERS_VERSION], -[ - AC_MSG_WARN([[$0 is deprecated, please use AX_LUA_HEADERS instead]]) -]) - - -dnl ========================================================================= -dnl AX_LUA_LIBS([ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND]) -dnl ========================================================================= -AC_DEFUN([AX_LUA_LIBS], -[ - dnl TODO Should this macro also check various -L flags? - - dnl Check for LUA_VERSION. - AC_MSG_CHECKING([if LUA_VERSION is defined]) - AS_IF([test "x$LUA_VERSION" != 'x'], - [AC_MSG_RESULT([yes])], - [ AC_MSG_RESULT([no]) - AC_MSG_ERROR([cannot check Lua libs without knowing LUA_VERSION]) - ]) - - dnl Make LUA_LIB a precious variable. - AC_ARG_VAR([LUA_LIB], [The Lua library, e.g. -llua5.1]) - - AS_IF([test "x$LUA_LIB" != 'x'], - [ dnl Check that LUA_LIBS works. - _ax_lua_saved_libs=$LIBS - LIBS="$LUA_LIB $LIBS" - AC_SEARCH_LIBS([lua_load], [], - [_ax_found_lua_libs='yes'], - [_ax_found_lua_libs='no']) - LIBS=$_ax_lua_saved_libs - - dnl Check the result. - AS_IF([test "x$_ax_found_lua_libs" != 'xyes'], - [AC_MSG_ERROR([cannot find libs for specified LUA_LIB])]) - ], - [ dnl First search for extra libs. - _ax_lua_extra_libs='' - - _ax_lua_saved_libs=$LIBS - LIBS="$LUA_LIB $LIBS" - AC_SEARCH_LIBS([exp], [m]) - AC_SEARCH_LIBS([dlopen], [dl]) - LIBS=$_ax_lua_saved_libs - - AS_IF([test "x$ac_cv_search_exp" != 'xno' && - test "x$ac_cv_search_exp" != 'xnone required'], - [_ax_lua_extra_libs="$_ax_lua_extra_libs $ac_cv_search_exp"]) - - AS_IF([test "x$ac_cv_search_dlopen" != 'xno' && - test "x$ac_cv_search_dlopen" != 'xnone required'], - [_ax_lua_extra_libs="$_ax_lua_extra_libs $ac_cv_search_dlopen"]) - - dnl Try to find the Lua libs. - _ax_lua_saved_libs=$LIBS - LIBS="$LUA_LIB $LIBS" - AC_SEARCH_LIBS([lua_load], - [ lua$LUA_VERSION \ - lua$LUA_SHORT_VERSION \ - lua-$LUA_VERSION \ - lua-$LUA_SHORT_VERSION \ - lua \ - ], - [_ax_found_lua_libs='yes'], - [_ax_found_lua_libs='no'], - [$_ax_lua_extra_libs]) - LIBS=$_ax_lua_saved_libs - - AS_IF([test "x$ac_cv_search_lua_load" != 'xno' && - test "x$ac_cv_search_lua_load" != 'xnone required'], - [LUA_LIB="$ac_cv_search_lua_load $_ax_lua_extra_libs"]) - ]) - - dnl Test the result and run user code. - AS_IF([test "x$_ax_found_lua_libs" = 'xyes'], [$1], - [m4_default([$2], [AC_MSG_ERROR([cannot find Lua libs])])]) -]) - - -dnl ========================================================================= -dnl AX_LUA_READLINE([ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND]) -dnl ========================================================================= -AC_DEFUN([AX_LUA_READLINE], -[ - AX_LIB_READLINE - AS_IF([test "x$ac_cv_header_readline_readline_h" != 'x' && - test "x$ac_cv_header_readline_history_h" != 'x'], - [ LUA_LIBS_CFLAGS="-DLUA_USE_READLINE $LUA_LIBS_CFLAGS" - $1 - ], - [$2]) -]) diff --git a/contrib/libucl/m4/gcov.m4 b/contrib/libucl/m4/gcov.m4 deleted file mode 100644 index a1359a0de64b..000000000000 --- a/contrib/libucl/m4/gcov.m4 +++ /dev/null @@ -1,89 +0,0 @@ -# SYNOPSIS -# -# Add code coverage support with gcov/lcov. -# -# AX_CODE_COVERAGE() -# -# DESCRIPTION -# -# Provides a --enable-coverage option which checks for available -# gcov/lcov binaries and provides ENABLE_CODE_COVERAGE conditional. -# -# LAST MODIFICATION -# -# $Id: coverage.m4 40881 2013-08-20 17:54:39Z damon $ -# -# COPYLEFT -# -# Copyright (c) 2012 Roy H. Stogner <roystgnr@ices.utexas.edu> -# Copyright (c) 2010 Karl W. Schulz <karl@ices.utexas.edu> -# -# Copying and distribution of this file, with or without modification, are -# permitted in any medium without royalty provided the copyright notice -# and this notice are preserved. - -AC_DEFUN([AX_CODE_COVERAGE], -[ - -AC_ARG_ENABLE(coverage, AC_HELP_STRING([--enable-coverage],[configure code coverage analysis tools])) - -HAVE_GCOV_TOOLS=0 - -GCOV_FLAGS="" - -if test "x$enable_coverage" = "xyes"; then - - # ---------------------------- - # Check for gcov/lcov binaries - # ---------------------------- - - AC_ARG_VAR([GCOV], [Coverage testing command]) - if test "x$GCOV" = "x"; then - AC_PATH_PROG(GCOV, gcov, no) - else - AC_PATH_PROG(GCOV, $GCOV, no) - fi - - AC_PATH_PROG(LCOV, lcov, no) - AC_PATH_PROG(GENHTML, genhtml) - - # ---------------------------------- - # include coverage compiler options - # ---------------------------------- - AC_MSG_CHECKING([for clang]) - - AC_COMPILE_IFELSE( - [AC_LANG_PROGRAM([], [[ - #ifndef __clang__ - not clang - #endif - ]])], - [CLANG=yes], [CLANG=no]) - - AC_MSG_RESULT([$CLANG]) - HAVE_GCOV_TOOLS=1 - COVERAGE_CFLAGS="-fprofile-arcs -ftest-coverage" - COVERAGE_LDFLAGS="--coverage -fprofile-arcs -ftest-coverage" - COVERAGE_OPTFLAGS="-O0" - - # Test for C... - CFLAGS="${GCOV_FLAGS} ${CFLAGS}" - CXXFLAGS="${GCOV_FLAGS} ${CXXFLAGS}" - if test "x$GCC" = "xyes" -a "x$CLANG" = "xno"; then - COVERAGE_LIBS="-lgcov" - else - COVERAGE_LIBS="" - fi -fi - -AC_SUBST([GCOV]) -AC_SUBST([LCOV]) -AC_SUBST([GENHTML]) -AC_SUBST([GENHTML_OPTIONS]) -AC_SUBST([COVERAGE_CFLAGS]) -AC_SUBST([COVERAGE_OPTFLAGS]) -AC_SUBST([COVERAGE_LDFLAGS]) -AC_SUBST([COVERAGE_LIBS]) -AM_CONDITIONAL(CODE_COVERAGE_ENABLED,test x$HAVE_GCOV_TOOLS = x1) - -]) diff --git a/contrib/libucl/python/MANIFEST.in b/contrib/libucl/python/MANIFEST.in deleted file mode 100644 index 336a4b3a7a07..000000000000 --- a/contrib/libucl/python/MANIFEST.in +++ /dev/null @@ -1,5 +0,0 @@ -include COPYING -recursive-include include *.h -recursive-include src *.h -recursive-include klib *.h -recursive-include uthash *.h diff --git a/contrib/libucl/python/setup.py b/contrib/libucl/python/setup.py deleted file mode 100644 index 8da832bac381..000000000000 --- a/contrib/libucl/python/setup.py +++ /dev/null @@ -1,75 +0,0 @@ -try: - from setuptools import setup, Extension - # setuptools doesn't support template param for MANIFEST.in - from setuptools.command.egg_info import manifest_maker - manifest_maker.template = 'python/MANIFEST.in' -except ImportError: - from distutils.core import setup, Extension - -import os -import sys - -LIB_ROOT = os.path.abspath(os.path.join(__file__, os.pardir, os.pardir)) -if os.getcwd() != LIB_ROOT: - os.chdir(LIB_ROOT) -if LIB_ROOT not in sys.path: - sys.path.append(LIB_ROOT) - -tests_require = [] - -if sys.version < '2.7': - tests_require.append('unittest2') - -uclmodule = Extension( - 'ucl', - libraries=['ucl', 'curl'], - sources=['python/src/uclmodule.c'], - include_dirs=['include'], - language='c', -) - -ucl_lib = { - 'sources': ['src/' + fn for fn in os.listdir('src') if fn.endswith('.c')], - 'include_dirs': ['include', 'src', 'uthash', 'klib'], - 'macros': [('CURL_FOUND', '1')], -} - -# sdist setup() will pull in the *.c files automatically, but not headers -# MANIFEST.in will include the headers for sdist only -template = 'python/MANIFEST.in' - -# distutils assume setup.py is in the root of the project -# we need to include C source from the parent so trick it -in_ucl_root = 'setup.py' in os.listdir('python') -if in_ucl_root: - os.link('python/setup.py', 'setup.py') - -setup( - name = 'ucl', - version = '0.8.1', - description = 'ucl parser and emitter', - ext_modules = [uclmodule], - template=template, # no longer supported with setuptools but doesn't hurt - libraries = [('ucl', ucl_lib)], - test_suite = 'tests', - tests_require = tests_require, - author = "Eitan Adler, Denis Volpato Martins", - author_email = "lists@eitanadler.com", - url = "https://github.com/vstakhov/libucl/", - license = "MIT", - classifiers = [ - "Development Status :: 3 - Alpha", - "Intended Audience :: Developers", - "License :: DFSG approved", - "License :: OSI Approved :: MIT License", - "Programming Language :: C", - "Programming Language :: Python :: 2", - "Programming Language :: Python :: 3", - "Programming Language :: Python :: Implementation :: CPython", - "Topic :: Software Development :: Libraries", - ] -) - -# clean up the trick after the build -if in_ucl_root: - os.unlink("setup.py") diff --git a/contrib/libucl/python/src/uclmodule.c b/contrib/libucl/python/src/uclmodule.c deleted file mode 100644 index d1051fbb0d12..000000000000 --- a/contrib/libucl/python/src/uclmodule.c +++ /dev/null @@ -1,335 +0,0 @@ -// Attempts to load a UCL structure from a string -#include <ucl.h> -#include <Python.h> - -static PyObject *SchemaError; - -static PyObject * -_basic_ucl_type (ucl_object_t const *obj) -{ - switch (obj->type) { - case UCL_INT: - return Py_BuildValue ("L", (long long)ucl_object_toint (obj)); - case UCL_FLOAT: - return Py_BuildValue ("d", ucl_object_todouble (obj)); - case UCL_STRING: - return Py_BuildValue ("s", ucl_object_tostring (obj)); - case UCL_BOOLEAN: - return PyBool_FromLong (ucl_object_toboolean (obj)); - case UCL_TIME: - return Py_BuildValue ("d", ucl_object_todouble (obj)); - case UCL_NULL: - Py_RETURN_NONE; - } - return NULL; -} - -static PyObject * -_iterate_valid_ucl (ucl_object_t const *obj) -{ - const ucl_object_t *tmp; - ucl_object_iter_t it = NULL; - - tmp = obj; - - while ((obj = ucl_object_iterate (tmp, &it, false))) { - PyObject *val; - - val = _basic_ucl_type(obj); - if (!val) { - PyObject *key = NULL; - - if (obj->key != NULL) { - key = Py_BuildValue("s", ucl_object_key(obj)); - } - - if (obj->type == UCL_OBJECT) { - const ucl_object_t *cur; - ucl_object_iter_t it_obj = NULL; - - val = PyDict_New(); - - while ((cur = ucl_object_iterate (obj, &it_obj, true))) { - PyObject *keyobj = Py_BuildValue("s",ucl_object_key(cur)); - PyDict_SetItem(val, keyobj, _iterate_valid_ucl(cur)); - } - } else if (obj->type == UCL_ARRAY) { - const ucl_object_t *cur; - ucl_object_iter_t it_obj = NULL; - - val = PyList_New(0); - - while ((cur = ucl_object_iterate (obj, &it_obj, true))) { - PyList_Append(val, _iterate_valid_ucl(cur)); - } - } else if (obj->type == UCL_USERDATA) { - // XXX: this should be - // PyBytes_FromStringAndSize; where is the - // length from? - val = PyBytes_FromString(obj->value.ud); - } - } - return val; - } - - PyErr_SetString(PyExc_SystemError, "unhandled type"); - return NULL; -} - -static PyObject * -_internal_load_ucl (char *uclstr) -{ - PyObject *ret; - struct ucl_parser *parser = - ucl_parser_new (UCL_PARSER_NO_TIME|UCL_PARSER_NO_IMPLICIT_ARRAYS); - bool r = ucl_parser_add_string(parser, uclstr, 0); - - if (r) { - if (ucl_parser_get_error (parser)) { - PyErr_SetString(PyExc_ValueError, ucl_parser_get_error(parser)); - ucl_parser_free(parser); - ret = NULL; - goto return_with_parser; - } else { - ucl_object_t *uclobj = ucl_parser_get_object(parser); - ret = _iterate_valid_ucl(uclobj); - ucl_object_unref(uclobj); - goto return_with_parser; - } - } - else { - PyErr_SetString(PyExc_ValueError, ucl_parser_get_error (parser)); - ret = NULL; - goto return_with_parser; - } - -return_with_parser: - ucl_parser_free(parser); - return ret; -} - -static PyObject* -ucl_load (PyObject *self, PyObject *args) -{ - char *uclstr; - - if (PyArg_ParseTuple(args, "z", &uclstr)) { - if (!uclstr) { - Py_RETURN_NONE; - } - - return _internal_load_ucl(uclstr); - } - - return NULL; -} - -static ucl_object_t * -_iterate_python (PyObject *obj) -{ - if (obj == Py_None) { - return ucl_object_new(); - } - else if (PyBool_Check (obj)) { - return ucl_object_frombool (obj == Py_True); - } -#if PY_MAJOR_VERSION < 3 - else if (PyInt_Check (obj)) { - return ucl_object_fromint (PyInt_AsLong (obj)); - } -#endif - else if (PyLong_Check (obj)) { - return ucl_object_fromint (PyLong_AsLong (obj)); - } - else if (PyFloat_Check (obj)) { - return ucl_object_fromdouble (PyFloat_AsDouble (obj)); - } - else if (PyUnicode_Check (obj)) { - ucl_object_t *ucl_str; - PyObject *str = PyUnicode_AsASCIIString(obj); - ucl_str = ucl_object_fromstring (PyBytes_AsString (str)); - Py_DECREF(str); - return ucl_str; - } -#if PY_MAJOR_VERSION < 3 - else if (PyString_Check (obj)) { - return ucl_object_fromstring (PyString_AsString (obj)); - } -#endif - else if (PyDict_Check(obj)) { - PyObject *key, *value; - Py_ssize_t pos = 0; - ucl_object_t *top, *elm; - char *keystr = NULL; - - top = ucl_object_typed_new (UCL_OBJECT); - - while (PyDict_Next(obj, &pos, &key, &value)) { - elm = _iterate_python(value); - - if (PyUnicode_Check(key)) { - PyObject *keyascii = PyUnicode_AsASCIIString(key); - keystr = PyBytes_AsString(keyascii); - Py_DECREF(keyascii); - } -#if PY_MAJOR_VERSION < 3 - else if (PyString_Check(key)) { - keystr = PyString_AsString(key); - } -#endif - else { - PyErr_SetString(PyExc_TypeError, "Unknown key type"); - return NULL; - } - - ucl_object_insert_key (top, elm, keystr, 0, true); - } - - return top; - } - else if (PySequence_Check(obj)) { - PyObject *value; - Py_ssize_t len, pos; - ucl_object_t *top, *elm; - - len = PySequence_Length(obj); - top = ucl_object_typed_new (UCL_ARRAY); - - for (pos = 0; pos < len; pos++) { - value = PySequence_GetItem(obj, pos); - elm = _iterate_python(value); - ucl_array_append(top, elm); - } - - return top; - } - else { - PyErr_SetString(PyExc_TypeError, "Unhandled object type"); - return NULL; - } - - return NULL; -} - -static PyObject * -ucl_dump (PyObject *self, PyObject *args) -{ - PyObject *obj; - ucl_emitter_t emitter; - ucl_object_t *root = NULL; - - emitter = UCL_EMIT_CONFIG; - - if (!PyArg_ParseTuple(args, "O|i", &obj, &emitter)) { - PyErr_SetString(PyExc_TypeError, "Unhandled object type"); - return NULL; - } - - if (emitter >= UCL_EMIT_MAX) { - PyErr_SetString(PyExc_TypeError, "Invalid emitter type"); - return NULL; - } - - if (obj == Py_None) { - Py_RETURN_NONE; - } - - root = _iterate_python(obj); - if (root) { - PyObject *ret; - char *buf; - - buf = (char *) ucl_object_emit (root, emitter); - ucl_object_unref (root); -#if PY_MAJOR_VERSION < 3 - ret = PyString_FromString (buf); -#else - ret = PyUnicode_FromString (buf); -#endif - free(buf); - - return ret; - } - - return NULL; -} - -static PyObject * -ucl_validate (PyObject *self, PyObject *args) -{ - PyObject *dataobj, *schemaobj; - ucl_object_t *data, *schema; - bool r; - struct ucl_schema_error err; - - if (!PyArg_ParseTuple (args, "OO", &schemaobj, &dataobj)) { - PyErr_SetString (PyExc_TypeError, "Unhandled object type"); - return NULL; - } - - schema = _iterate_python(schemaobj); - if (!schema) - return NULL; - - data = _iterate_python(dataobj); - if (!data) - return NULL; - - // validation - r = ucl_object_validate (schema, data, &err); - ucl_object_unref (schema); - ucl_object_unref (data); - - if (!r) { - PyErr_SetString (SchemaError, err.msg); - return NULL; - } - - Py_RETURN_TRUE; -} - -static PyMethodDef uclMethods[] = { - {"load", ucl_load, METH_VARARGS, "Load UCL from stream"}, - {"dump", ucl_dump, METH_VARARGS, "Dump UCL to stream"}, - {"validate", ucl_validate, METH_VARARGS, "Validate ucl stream against schema"}, - {NULL, NULL, 0, NULL} -}; - -static void -init_macros(PyObject *mod) -{ - PyModule_AddIntMacro(mod, UCL_EMIT_JSON); - PyModule_AddIntMacro(mod, UCL_EMIT_JSON_COMPACT); - PyModule_AddIntMacro(mod, UCL_EMIT_CONFIG); - PyModule_AddIntMacro(mod, UCL_EMIT_YAML); - PyModule_AddIntMacro(mod, UCL_EMIT_MSGPACK); - - SchemaError = PyErr_NewException("ucl.SchemaError", NULL, NULL); - Py_INCREF(SchemaError); - PyModule_AddObject(mod, "SchemaError", SchemaError); -} - -#if PY_MAJOR_VERSION >= 3 -static struct PyModuleDef uclmodule = { - PyModuleDef_HEAD_INIT, - "ucl", - NULL, - -1, - uclMethods -}; - -PyMODINIT_FUNC -PyInit_ucl (void) -{ - PyObject *mod = PyModule_Create (&uclmodule); - init_macros (mod); - - return mod; -} -#else -void initucl (void) -{ - PyObject *mod = Py_InitModule ("ucl", uclMethods); - init_macros (mod); -} -#endif diff --git a/contrib/libucl/python/tests/__init__.py b/contrib/libucl/python/tests/__init__.py deleted file mode 100644 index e69de29bb2d1..000000000000 --- a/contrib/libucl/python/tests/__init__.py +++ /dev/null diff --git a/contrib/libucl/python/tests/compat.py b/contrib/libucl/python/tests/compat.py deleted file mode 100644 index 50138262e9b7..000000000000 --- a/contrib/libucl/python/tests/compat.py +++ /dev/null @@ -1,8 +0,0 @@ -try: - import unittest2 as unittest -except ImportError: - import unittest - -# Python 2.7 - 3.1 -if not hasattr(unittest.TestCase, 'assertRaisesRegex'): - unittest.TestCase.assertRaisesRegex = unittest.TestCase.assertRaisesRegexp diff --git a/contrib/libucl/python/tests/test_dump.py b/contrib/libucl/python/tests/test_dump.py deleted file mode 100644 index 369241468509..000000000000 --- a/contrib/libucl/python/tests/test_dump.py +++ /dev/null @@ -1,66 +0,0 @@ -from .compat import unittest -import ucl -import sys - -class DumpTest(unittest.TestCase): - def test_no_args(self): - with self.assertRaises(TypeError): - ucl.dump() - - def test_none(self): - self.assertEqual(ucl.dump(None), None) - - def test_null(self): - data = { "a" : None } - valid = "a = null;\n" - self.assertEqual(ucl.dump(data), valid) - - def test_int(self): - data = { "a" : 1 } - valid = "a = 1;\n" - self.assertEqual(ucl.dump(data), valid) - - def test_nested_int(self): - data = { "a" : { "b" : 1 } } - valid = "a {\n b = 1;\n}\n" - self.assertEqual(ucl.dump(data), valid) - - def test_int_array(self): - data = { "a" : [1,2,3,4] } - valid = "a [\n 1,\n 2,\n 3,\n 4,\n]\n" - self.assertEqual(ucl.dump(data), valid) - - def test_str(self): - data = { "a" : "b" } - valid = "a = \"b\";\n" - self.assertEqual(ucl.dump(data), valid) - - @unittest.skipIf(sys.version_info[0] > 2, "Python3 uses unicode only") - def test_unicode(self): - data = { unicode("a") : unicode("b") } - valid = unicode("a = \"b\";\n") - self.assertEqual(ucl.dump(data), valid) - - def test_float(self): - data = { "a" : 1.1 } - valid = "a = 1.100000;\n" - self.assertEqual(ucl.dump(data), valid) - - def test_boolean(self): - data = { "a" : True, "b" : False } - valid = [ - "a = true;\nb = false;\n", - "b = false;\na = true;\n" - ] - self.assertIn(ucl.dump(data), valid) - - def test_empty_ucl(self): - self.assertEqual(ucl.dump({}), "") - - def test_json(self): - data = { "a" : 1, "b": "bleh;" } - valid = [ - '{\n "a": 1,\n "b": "bleh;"\n}', - '{\n "b": "bleh;",\n "a": 1\n}' - ] - self.assertIn(ucl.dump(data, ucl.UCL_EMIT_JSON), valid) diff --git a/contrib/libucl/python/tests/test_example.py b/contrib/libucl/python/tests/test_example.py deleted file mode 100644 index f0785531f4e2..000000000000 --- a/contrib/libucl/python/tests/test_example.py +++ /dev/null @@ -1,59 +0,0 @@ -from .compat import unittest -import json -import ucl - -_ucl_inp = ''' -param = value; -section { - param = value; - param1 = value1; - flag = true; - number = 10k; - time = 0.2s; - string = "something"; - subsection { - host = { - host = "hostname"; - port = 900; - } - host = { - host = "hostname"; - port = 901; - } - } -} -''' - -_json_res = { - 'param': 'value', - 'section': { - 'param': 'value', - 'param1': 'value1', - 'flag': True, - 'number': 10000, - 'time': '0.2s', - 'string': 'something', - 'subsection': { - 'host': [ - { - 'host': 'hostname', - 'port': 900, - }, - { - 'host': 'hostname', - 'port': 901, - } - ] - } - } -} - -class TestExample(unittest.TestCase): - def test_example(self): - # load in sample UCL - u = ucl.load(_ucl_inp) - - # Output and read back the JSON - uj = json.loads(json.dumps(u)) - - self.assertEqual(uj, _json_res) diff --git a/contrib/libucl/python/tests/test_load.py b/contrib/libucl/python/tests/test_load.py deleted file mode 100644 index 73d43188f3d5..000000000000 --- a/contrib/libucl/python/tests/test_load.py +++ /dev/null @@ -1,122 +0,0 @@ -from .compat import unittest -import ucl - -class LoadTest(unittest.TestCase): - def test_no_args(self): - with self.assertRaises(TypeError): - ucl.load() - - def test_multi_args(self): - with self.assertRaises(TypeError): - ucl.load(0,0) - - def test_none(self): - self.assertEqual(ucl.load(None), None) - - def test_null(self): - data = "a: null" - valid = { "a" : None } - self.assertEqual(ucl.load(data), valid) - - def test_int(self): - data = "a : 1" - valid = { "a" : 1 } - self.assertEqual(ucl.load(data), valid) - - def test_braced_int(self): - data = "{a : 1}" - valid = { "a" : 1 } - self.assertEqual(ucl.load(data), valid) - - def test_nested_int(self): - data = "a : { b : 1 }" - valid = { "a" : { "b" : 1 } } - self.assertEqual(ucl.load(data), valid) - - def test_str(self): - data = "a : b" - valid = { "a" : "b" } - self.assertEqual(ucl.load(data), valid) - - def test_float(self): - data = "a : 1.1" - valid = {"a" : 1.1} - self.assertEqual(ucl.load(data), valid) - - def test_boolean(self): - data = ( - "a : True;" \ - "b : False" - ) - valid = { "a" : True, "b" : False } - self.assertEqual(ucl.load(data), valid) - - def test_empty_ucl(self): - self.assertEqual(ucl.load("{}"), {}) - - def test_single_brace(self): - self.assertEqual(ucl.load("{"), {}) - - def test_single_back_brace(self): - self.assertEqual(ucl.load("}"), {}) - - def test_single_square_forward(self): - self.assertEqual(ucl.load("["), []) - - def test_invalid_ucl(self): - with self.assertRaisesRegex(ValueError, "unfinished key$"): - ucl.load('{ "var"') - - def test_comment_ignored(self): - self.assertEqual(ucl.load("{/*1*/}"), {}) - - def test_1_in(self): - valid = { - 'key1': [ - 'value', - 'value2', - 'value;', - 1.0, - -0xdeadbeef, - '0xdeadbeef.1', - '0xreadbeef', - -1e-10, - 1, - True, - False, - True, - ] - } - with open("../tests/basic/1.in", "r") as in1: - self.assertEqual(ucl.load(in1.read()), valid) - - def test_every_type(self): - data = ("""{ - "key1": value; - "key2": value2; - "key3": "value;" - "key4": 1.0, - "key5": -0xdeadbeef - "key6": 0xdeadbeef.1 - "key7": 0xreadbeef - "key8": -1e-10, - "key9": 1 - "key10": true - "key11": no - "key12": yes - }""") - valid = { - 'key1': 'value', - 'key2': 'value2', - 'key3': 'value;', - 'key4': 1.0, - 'key5': -3735928559, - 'key6': '0xdeadbeef.1', - 'key7': '0xreadbeef', - 'key8': -1e-10, - 'key9': 1, - 'key10': True, - 'key11': False, - 'key12': True, - } - self.assertEqual(ucl.load(data), valid) diff --git a/contrib/libucl/python/tests/test_validation.py b/contrib/libucl/python/tests/test_validation.py deleted file mode 100644 index f7c853ad69a7..000000000000 --- a/contrib/libucl/python/tests/test_validation.py +++ /dev/null @@ -1,50 +0,0 @@ -from .compat import unittest -import ucl -import json -import os.path -import glob -import re - -TESTS_SCHEMA_FOLDER = '../tests/schema/*.json' - -comment_re = re.compile('\/\*((?!\*\/).)*?\*\/', re.DOTALL | re.MULTILINE) -def json_remove_comments(content): - return comment_re.sub('', content) - -class ValidationTest(unittest.TestCase): - def validate(self, jsonfile): - def perform_test(schema, data, valid, description): - msg = '%s (valid=%r)' % (description, valid) - if valid: - self.assertTrue(ucl.validate(schema, data), msg) - else: - with self.assertRaises(ucl.SchemaError): - ucl.validate(schema, data) - self.fail(msg) # fail() will be called only if SchemaError is not raised - - with open(jsonfile) as f: - try: - # data = json.load(f) - data = json.loads(json_remove_comments(f.read())) - except ValueError as e: - raise self.skipTest('Failed to load JSON: %s' % str(e)) - - for testgroup in data: - for test in testgroup['tests']: - perform_test(testgroup['schema'], test['data'], - test['valid'], test['description']) - - @classmethod - def setupValidationTests(cls): - """Creates each test dynamically from a folder""" - def test_gen(filename): - def run_test(self): - self.validate(filename) - return run_test - - for jsonfile in glob.glob(TESTS_SCHEMA_FOLDER): - testname = os.path.splitext(os.path.basename(jsonfile))[0] - setattr(cls, 'test_%s' % testname, test_gen(jsonfile)) - - -ValidationTest.setupValidationTests() diff --git a/contrib/libucl/python/ucl.pyi b/contrib/libucl/python/ucl.pyi deleted file mode 100644 index 79fa2901ba9f..000000000000 --- a/contrib/libucl/python/ucl.pyi +++ /dev/null @@ -1,15 +0,0 @@ -# Stubs for ucl (Python 3.6) -# -# NOTE: This dynamically typed stub was automatically generated by stubgen. - -UCL_EMIT_CONFIG = ... # type: int -UCL_EMIT_JSON = ... # type: int -UCL_EMIT_JSON_COMPACT = ... # type: int -UCL_EMIT_MSGPACK = ... # type: int -UCL_EMIT_YAML = ... # type: int - -def dump(*args, **kwargs): ... -def load(*args, **kwargs): ... -def validate(*args, **kwargs): ... - -class SchemaError(Exception): ... diff --git a/contrib/libucl/src/Makefile.am b/contrib/libucl/src/Makefile.am deleted file mode 100644 index 80ce5b185b83..000000000000 --- a/contrib/libucl/src/Makefile.am +++ /dev/null @@ -1,30 +0,0 @@ -libucl_common_cflags= -I$(top_srcdir)/src \ - -I$(top_srcdir)/include \ - -I$(top_srcdir)/uthash \ - -I$(top_srcdir)/klib \ - -Wall -W -Wno-unused-parameter -Wno-pointer-sign -lib_LTLIBRARIES= libucl.la -libucl_la_SOURCES= ucl_emitter.c \ - ucl_emitter_streamline.c \ - ucl_emitter_utils.c \ - ucl_hash.c \ - ucl_parser.c \ - ucl_schema.c \ - ucl_util.c \ - ucl_msgpack.c \ - ucl_sexp.c -libucl_la_CFLAGS= $(libucl_common_cflags) \ - @CURL_CFLAGS@ -libucl_la_LDFLAGS = -version-info @SO_VERSION@ -libucl_la_LIBADD= @LIBFETCH_LIBS@ \ - @LIBCRYPTO_LIB@ \ - @LIBREGEX_LIB@ \ - @CURL_LIBS@ - -include_HEADERS= $(top_srcdir)/include/ucl.h \ - $(top_srcdir)/include/ucl++.h -noinst_HEADERS= ucl_internal.h \ - mum.h \ - ucl_hash.h \ - ucl_chartable.h \ - tree.h diff --git a/contrib/libucl/src/mum.h b/contrib/libucl/src/mum.h index 148161a3ec58..318efea50268 100644 --- a/contrib/libucl/src/mum.h +++ b/contrib/libucl/src/mum.h @@ -69,11 +69,9 @@ typedef unsigned __int64 uint64_t; #endif #endif -#if 0 #if defined(__GNUC__) && ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 9) || (__GNUC__ > 4)) #define _MUM_FRESH_GCC #endif -#endif #if defined(__GNUC__) && !defined(__llvm__) && defined(_MUM_FRESH_GCC) #define _MUM_ATTRIBUTE_UNUSED __attribute__((unused)) diff --git a/contrib/libucl/src/ucl_emitter.c b/contrib/libucl/src/ucl_emitter.c index 4f4465dfbf4a..97d8f618021f 100644 --- a/contrib/libucl/src/ucl_emitter.c +++ b/contrib/libucl/src/ucl_emitter.c @@ -47,9 +47,9 @@ static void ucl_emitter_common_elt (struct ucl_emitter_context *ctx, static void ucl_emit_ ## type ## _elt (struct ucl_emitter_context *ctx, \ const ucl_object_t *obj, bool first, bool print_key); \ static void ucl_emit_ ## type ## _start_obj (struct ucl_emitter_context *ctx, \ - const ucl_object_t *obj, bool print_key); \ + const ucl_object_t *obj, bool first, bool print_key); \ static void ucl_emit_ ## type## _start_array (struct ucl_emitter_context *ctx, \ - const ucl_object_t *obj, bool print_key); \ + const ucl_object_t *obj, bool first, bool print_key); \ static void ucl_emit_ ##type## _end_object (struct ucl_emitter_context *ctx, \ const ucl_object_t *obj); \ static void ucl_emit_ ##type## _end_array (struct ucl_emitter_context *ctx, \ @@ -248,12 +248,26 @@ ucl_emitter_common_end_array (struct ucl_emitter_context *ctx, */ static void ucl_emitter_common_start_array (struct ucl_emitter_context *ctx, - const ucl_object_t *obj, bool print_key, bool compact) + const ucl_object_t *obj, bool first, bool print_key, bool compact) { const ucl_object_t *cur; ucl_object_iter_t iter = NULL; const struct ucl_emitter_functions *func = ctx->func; - bool first = true; + bool first_key = true; + + if (ctx->id != UCL_EMIT_CONFIG && !first) { + if (compact) { + func->ucl_emitter_append_character (',', 1, func->ud); + } + else { + if (ctx->id == UCL_EMIT_YAML && ctx->indent == 0) { + func->ucl_emitter_append_len ("\n", 1, func->ud); + } else { + func->ucl_emitter_append_len (",\n", 2, func->ud); + } + } + ucl_add_tabs (func, ctx->indent, compact); + } ucl_emitter_print_key (print_key, ctx, obj, compact); @@ -269,16 +283,16 @@ ucl_emitter_common_start_array (struct ucl_emitter_context *ctx, if (obj->type == UCL_ARRAY) { /* explicit array */ while ((cur = ucl_object_iterate (obj, &iter, true)) != NULL) { - ucl_emitter_common_elt (ctx, cur, first, false, compact); - first = false; + ucl_emitter_common_elt (ctx, cur, first_key, false, compact); + first_key = false; } } else { /* implicit array */ cur = obj; while (cur) { - ucl_emitter_common_elt (ctx, cur, first, false, compact); - first = false; + ucl_emitter_common_elt (ctx, cur, first_key, false, compact); + first_key = false; cur = cur->next; } } @@ -294,12 +308,26 @@ ucl_emitter_common_start_array (struct ucl_emitter_context *ctx, */ static void ucl_emitter_common_start_object (struct ucl_emitter_context *ctx, - const ucl_object_t *obj, bool print_key, bool compact) + const ucl_object_t *obj, bool first, bool print_key, bool compact) { ucl_hash_iter_t it = NULL; const ucl_object_t *cur, *elt; const struct ucl_emitter_functions *func = ctx->func; - bool first = true; + bool first_key = true; + + if (ctx->id != UCL_EMIT_CONFIG && !first) { + if (compact) { + func->ucl_emitter_append_character (',', 1, func->ud); + } + else { + if (ctx->id == UCL_EMIT_YAML && ctx->indent == 0) { + func->ucl_emitter_append_len ("\n", 1, func->ud); + } else { + func->ucl_emitter_append_len (",\n", 2, func->ud); + } + } + ucl_add_tabs (func, ctx->indent, compact); + } ucl_emitter_print_key (print_key, ctx, obj, compact); /* @@ -320,13 +348,13 @@ ucl_emitter_common_start_object (struct ucl_emitter_context *ctx, if (ctx->id == UCL_EMIT_CONFIG) { LL_FOREACH (cur, elt) { - ucl_emitter_common_elt (ctx, elt, first, true, compact); + ucl_emitter_common_elt (ctx, elt, first_key, true, compact); } } else { /* Expand implicit arrays */ if (cur->next != NULL) { - if (!first) { + if (!first_key) { if (compact) { func->ucl_emitter_append_character (',', 1, func->ud); } @@ -335,15 +363,15 @@ ucl_emitter_common_start_object (struct ucl_emitter_context *ctx, } } ucl_add_tabs (func, ctx->indent, compact); - ucl_emitter_common_start_array (ctx, cur, true, compact); + ucl_emitter_common_start_array (ctx, cur, first_key, true, compact); ucl_emitter_common_end_array (ctx, cur, compact); } else { - ucl_emitter_common_elt (ctx, cur, first, true, compact); + ucl_emitter_common_elt (ctx, cur, first_key, true, compact); } } - first = false; + first_key = false; } } @@ -446,11 +474,11 @@ ucl_emitter_common_elt (struct ucl_emitter_context *ctx, ucl_emitter_finish_object (ctx, obj, compact, !print_key); break; case UCL_OBJECT: - ucl_emitter_common_start_object (ctx, obj, print_key, compact); + ucl_emitter_common_start_object (ctx, obj, true, print_key, compact); ucl_emitter_common_end_object (ctx, obj, compact); break; case UCL_ARRAY: - ucl_emitter_common_start_array (ctx, obj, print_key, compact); + ucl_emitter_common_start_array (ctx, obj, true, print_key, compact); ucl_emitter_common_end_array (ctx, obj, compact); break; case UCL_USERDATA: @@ -490,12 +518,12 @@ ucl_emitter_common_elt (struct ucl_emitter_context *ctx, ucl_emitter_common_elt (ctx, obj, first, print_key, (compact)); \ } \ static void ucl_emit_ ## type ## _start_obj (struct ucl_emitter_context *ctx, \ - const ucl_object_t *obj, bool print_key) { \ - ucl_emitter_common_start_object (ctx, obj, print_key, (compact)); \ + const ucl_object_t *obj, bool first, bool print_key) { \ + ucl_emitter_common_start_object (ctx, obj, first, print_key, (compact)); \ } \ static void ucl_emit_ ## type## _start_array (struct ucl_emitter_context *ctx, \ - const ucl_object_t *obj, bool print_key) { \ - ucl_emitter_common_start_array (ctx, obj, print_key, (compact)); \ + const ucl_object_t *obj, bool first, bool print_key) { \ + ucl_emitter_common_start_array (ctx, obj, first, print_key, (compact)); \ } \ static void ucl_emit_ ##type## _end_object (struct ucl_emitter_context *ctx, \ const ucl_object_t *obj) { \ @@ -513,7 +541,7 @@ UCL_EMIT_TYPE_IMPL(yaml, false) static void ucl_emit_msgpack_elt (struct ucl_emitter_context *ctx, - const ucl_object_t *obj, bool first, bool print_key) + const ucl_object_t *obj, bool _first, bool print_key) { ucl_object_iter_t it; struct ucl_object_userdata *ud; @@ -556,7 +584,7 @@ ucl_emit_msgpack_elt (struct ucl_emitter_context *ctx, case UCL_OBJECT: ucl_emitter_print_key_msgpack (print_key, ctx, obj); - ucl_emit_msgpack_start_obj (ctx, obj, print_key); + ucl_emit_msgpack_start_obj (ctx, obj, false, print_key); it = NULL; while ((cur = ucl_object_iterate (obj, &it, true)) != NULL) { @@ -575,7 +603,7 @@ ucl_emit_msgpack_elt (struct ucl_emitter_context *ctx, case UCL_ARRAY: ucl_emitter_print_key_msgpack (print_key, ctx, obj); - ucl_emit_msgpack_start_array (ctx, obj, print_key); + ucl_emit_msgpack_start_array (ctx, obj, false, print_key); it = NULL; while ((cur = ucl_object_iterate (obj, &it, true)) != NULL) { @@ -601,14 +629,14 @@ ucl_emit_msgpack_elt (struct ucl_emitter_context *ctx, static void ucl_emit_msgpack_start_obj (struct ucl_emitter_context *ctx, - const ucl_object_t *obj, bool print_key) + const ucl_object_t *obj, bool _first, bool _print_key) { ucl_emitter_print_object_msgpack (ctx, obj->len); } static void ucl_emit_msgpack_start_array (struct ucl_emitter_context *ctx, - const ucl_object_t *obj, bool print_key) + const ucl_object_t *obj, bool _first, bool _print_key) { ucl_emitter_print_array_msgpack (ctx, obj->len); } diff --git a/contrib/libucl/src/ucl_emitter_streamline.c b/contrib/libucl/src/ucl_emitter_streamline.c index a7178c5d74b0..8ca86fa081c9 100644 --- a/contrib/libucl/src/ucl_emitter_streamline.c +++ b/contrib/libucl/src/ucl_emitter_streamline.c @@ -103,18 +103,19 @@ ucl_object_emit_streamline_start_container (struct ucl_emitter_context *ctx, top = sctx->containers; st = malloc (sizeof (*st)); if (st != NULL) { - if (top != NULL && !top->is_array) { + st->empty = true; + if (top && !top->is_array) { print_key = true; } - st->empty = true; + st->obj = obj; if (obj != NULL && obj->type == UCL_ARRAY) { st->is_array = true; - sctx->ops->ucl_emitter_start_array (ctx, obj, print_key); + sctx->ops->ucl_emitter_start_array (ctx, obj, top == NULL, print_key); } else { st->is_array = false; - sctx->ops->ucl_emitter_start_object (ctx, obj, print_key); + sctx->ops->ucl_emitter_start_object (ctx, obj, top == NULL, print_key); } LL_PREPEND (sctx->containers, st); } diff --git a/contrib/libucl/src/ucl_hash.c b/contrib/libucl/src/ucl_hash.c index a74dfcdee68e..0208cfd29c9a 100644 --- a/contrib/libucl/src/ucl_hash.c +++ b/contrib/libucl/src/ucl_hash.c @@ -32,12 +32,12 @@ struct ucl_hash_elt { const ucl_object_t *obj; - size_t ar_idx; + struct ucl_hash_elt *prev, *next; }; struct ucl_hash_struct { void *hash; - kvec_t(const ucl_object_t *) ar; + struct ucl_hash_elt *head; bool caseless; }; @@ -45,7 +45,6 @@ static uint64_t ucl_hash_seed (void) { static uint64_t seed; - if (seed == 0) { #ifdef UCL_RANDOM_FUNCTION seed = UCL_RANDOM_FUNCTION; @@ -115,7 +114,7 @@ ucl_hash_equal (const ucl_object_t *k1, const ucl_object_t *k2) return 0; } -KHASH_INIT (ucl_hash_node, const ucl_object_t *, struct ucl_hash_elt, 1, +KHASH_INIT (ucl_hash_node, const ucl_object_t *, struct ucl_hash_elt *, 1, ucl_hash_func, ucl_hash_equal) static inline uint32_t @@ -227,7 +226,7 @@ ucl_hash_caseless_equal (const ucl_object_t *k1, const ucl_object_t *k2) return 0; } -KHASH_INIT (ucl_hash_caseless_node, const ucl_object_t *, struct ucl_hash_elt, 1, +KHASH_INIT (ucl_hash_caseless_node, const ucl_object_t *, struct ucl_hash_elt *, 1, ucl_hash_caseless_func, ucl_hash_caseless_equal) ucl_hash_t* @@ -238,8 +237,7 @@ ucl_hash_create (bool ignore_case) new = UCL_ALLOC (sizeof (ucl_hash_t)); if (new != NULL) { void *h; - kv_init (new->ar); - + new->head = NULL; new->caseless = ignore_case; if (ignore_case) { h = (void *)kh_init (ucl_hash_caseless_node); @@ -258,7 +256,6 @@ ucl_hash_create (bool ignore_case) void ucl_hash_destroy (ucl_hash_t* hashlin, ucl_hash_free_func func) { - const ucl_object_t *cur, *tmp; if (hashlin == NULL) { return; @@ -269,10 +266,11 @@ void ucl_hash_destroy (ucl_hash_t* hashlin, ucl_hash_free_func func) khash_t(ucl_hash_node) *h = (khash_t(ucl_hash_node) *) hashlin->hash; khiter_t k; + const ucl_object_t *cur, *tmp; for (k = kh_begin (h); k != kh_end (h); ++k) { if (kh_exist (h, k)) { - cur = (kh_value (h, k)).obj; + cur = (kh_value (h, k))->obj; while (cur != NULL) { tmp = cur->next; func (__DECONST (ucl_object_t *, cur)); @@ -293,7 +291,12 @@ void ucl_hash_destroy (ucl_hash_t* hashlin, ucl_hash_free_func func) kh_destroy (ucl_hash_node, h); } - kv_destroy (hashlin->ar); + struct ucl_hash_elt *cur, *tmp; + + DL_FOREACH_SAFE(hashlin->head, cur, tmp) { + UCL_FREE(sizeof(*cur), cur); + } + UCL_FREE (sizeof (*hashlin), hashlin); } @@ -303,7 +306,7 @@ ucl_hash_insert (ucl_hash_t* hashlin, const ucl_object_t *obj, { khiter_t k; int ret; - struct ucl_hash_elt *elt; + struct ucl_hash_elt **pelt, *elt; if (hashlin == NULL) { return false; @@ -314,10 +317,14 @@ ucl_hash_insert (ucl_hash_t* hashlin, const ucl_object_t *obj, hashlin->hash; k = kh_put (ucl_hash_caseless_node, h, obj, &ret); if (ret > 0) { - elt = &kh_value (h, k); - kv_push_safe (const ucl_object_t *, hashlin->ar, obj, e0); + elt = UCL_ALLOC(sizeof(*elt)); + pelt = &kh_value (h, k); + *pelt = elt; + DL_APPEND(hashlin->head, elt); elt->obj = obj; - elt->ar_idx = kv_size (hashlin->ar) - 1; + } + else if (ret < 0) { + goto e0; } } else { @@ -325,10 +332,11 @@ ucl_hash_insert (ucl_hash_t* hashlin, const ucl_object_t *obj, hashlin->hash; k = kh_put (ucl_hash_node, h, obj, &ret); if (ret > 0) { - elt = &kh_value (h, k); - kv_push_safe (const ucl_object_t *, hashlin->ar, obj, e0); + elt = UCL_ALLOC(sizeof(*elt)); + pelt = &kh_value (h, k); + *pelt = elt; + DL_APPEND(hashlin->head, elt); elt->obj = obj; - elt->ar_idx = kv_size (hashlin->ar) - 1; } else if (ret < 0) { goto e0; } @@ -343,7 +351,7 @@ void ucl_hash_replace (ucl_hash_t* hashlin, const ucl_object_t *old, { khiter_t k; int ret; - struct ucl_hash_elt elt, *pelt; + struct ucl_hash_elt *elt, *nelt; if (hashlin == NULL) { return; @@ -354,13 +362,14 @@ void ucl_hash_replace (ucl_hash_t* hashlin, const ucl_object_t *old, hashlin->hash; k = kh_put (ucl_hash_caseless_node, h, old, &ret); if (ret == 0) { - elt = kh_value (h, k); + elt = kh_value(h, k); kh_del (ucl_hash_caseless_node, h, k); k = kh_put (ucl_hash_caseless_node, h, new, &ret); - pelt = &kh_value (h, k); - pelt->obj = new; - pelt->ar_idx = elt.ar_idx; - kv_A (hashlin->ar, elt.ar_idx) = new; + nelt = UCL_ALLOC(sizeof(*nelt)); + nelt->obj = new; + kh_value(h, k) = nelt; + DL_REPLACE_ELEM(hashlin->head, elt, nelt); + UCL_FREE(sizeof(*elt), elt); } } else { @@ -371,17 +380,17 @@ void ucl_hash_replace (ucl_hash_t* hashlin, const ucl_object_t *old, elt = kh_value (h, k); kh_del (ucl_hash_node, h, k); k = kh_put (ucl_hash_node, h, new, &ret); - pelt = &kh_value (h, k); - pelt->obj = new; - pelt->ar_idx = elt.ar_idx; - kv_A (hashlin->ar, elt.ar_idx) = new; + nelt = UCL_ALLOC(sizeof(*nelt)); + nelt->obj = new; + kh_value(h, k) = nelt; + DL_REPLACE_ELEM(hashlin->head, elt, nelt); + UCL_FREE(sizeof(*elt), elt); } } } struct ucl_hash_real_iter { - const ucl_object_t **cur; - const ucl_object_t **end; + const struct ucl_hash_elt *cur; }; #define UHI_SETERR(ep, ern) {if (ep != NULL) *ep = (ern);} @@ -405,13 +414,13 @@ ucl_hash_iterate2 (ucl_hash_t *hashlin, ucl_hash_iter_t *iter, int *ep) return NULL; } - it->cur = &hashlin->ar.a[0]; - it->end = it->cur + hashlin->ar.n; + it->cur = hashlin->head; } UHI_SETERR(ep, 0); - if (it->cur < it->end) { - ret = *it->cur++; + if (it->cur) { + ret = it->cur->obj; + it->cur = it->cur->next; } else { UCL_FREE (sizeof (*it), it); @@ -429,7 +438,7 @@ ucl_hash_iter_has_next (ucl_hash_t *hashlin, ucl_hash_iter_t iter) { struct ucl_hash_real_iter *it = (struct ucl_hash_real_iter *)(iter); - return it->cur < it->end - 1; + return it->cur != NULL; } @@ -454,7 +463,7 @@ ucl_hash_search (ucl_hash_t* hashlin, const char *key, unsigned keylen) k = kh_get (ucl_hash_caseless_node, h, &search); if (k != kh_end (h)) { - elt = &kh_value (h, k); + elt = kh_value (h, k); ret = elt->obj; } } @@ -463,7 +472,7 @@ ucl_hash_search (ucl_hash_t* hashlin, const char *key, unsigned keylen) hashlin->hash; k = kh_get (ucl_hash_node, h, &search); if (k != kh_end (h)) { - elt = &kh_value (h, k); + elt = kh_value (h, k); ret = elt->obj; } } @@ -476,7 +485,6 @@ ucl_hash_delete (ucl_hash_t* hashlin, const ucl_object_t *obj) { khiter_t k; struct ucl_hash_elt *elt; - size_t i; if (hashlin == NULL) { return; @@ -488,16 +496,10 @@ ucl_hash_delete (ucl_hash_t* hashlin, const ucl_object_t *obj) k = kh_get (ucl_hash_caseless_node, h, obj); if (k != kh_end (h)) { - elt = &kh_value (h, k); - i = elt->ar_idx; - kv_del (const ucl_object_t *, hashlin->ar, elt->ar_idx); + elt = kh_value (h, k); + DL_DELETE(hashlin->head, elt); kh_del (ucl_hash_caseless_node, h, k); - - /* Update subsequent elts */ - for (; i < hashlin->ar.n; i ++) { - elt = &kh_value (h, i); - elt->ar_idx --; - } + UCL_FREE(sizeof(*elt), elt); } } else { @@ -505,16 +507,10 @@ ucl_hash_delete (ucl_hash_t* hashlin, const ucl_object_t *obj) hashlin->hash; k = kh_get (ucl_hash_node, h, obj); if (k != kh_end (h)) { - elt = &kh_value (h, k); - i = elt->ar_idx; - kv_del (const ucl_object_t *, hashlin->ar, elt->ar_idx); + elt = kh_value (h, k); + DL_DELETE(hashlin->head, elt); kh_del (ucl_hash_node, h, k); - - /* Update subsequent elts */ - for (; i < hashlin->ar.n; i ++) { - elt = &kh_value (h, i); - elt->ar_idx --; - } + UCL_FREE(sizeof(*elt), elt); } } } @@ -525,9 +521,7 @@ bool ucl_hash_reserve (ucl_hash_t *hashlin, size_t sz) return false; } - if (sz > hashlin->ar.m) { - kv_resize_safe (const ucl_object_t *, hashlin->ar, sz, e0); - + if (sz > kh_size((khash_t(ucl_hash_node) *)hashlin->hash)) { if (hashlin->caseless) { khash_t(ucl_hash_caseless_node) *h = (khash_t( ucl_hash_caseless_node) *) @@ -540,8 +534,6 @@ bool ucl_hash_reserve (ucl_hash_t *hashlin, size_t sz) } } return true; -e0: - return false; } static int @@ -591,27 +583,27 @@ ucl_lc_cmp (const char *s, const char *d, size_t l) static int ucl_hash_cmp_icase (const void *a, const void *b) { - const ucl_object_t *oa = *(const ucl_object_t **)a, - *ob = *(const ucl_object_t **)b; + const struct ucl_hash_elt *oa = (const struct ucl_hash_elt *)a, + *ob = (const struct ucl_hash_elt *)b; - if (oa->keylen == ob->keylen) { - return ucl_lc_cmp (oa->key, ob->key, oa->keylen); + if (oa->obj->keylen == ob->obj->keylen) { + return ucl_lc_cmp (oa->obj->key, ob->obj->key, oa->obj->keylen); } - return ((int)(oa->keylen)) - ob->keylen; + return ((int)(oa->obj->keylen)) - ob->obj->keylen; } static int ucl_hash_cmp_case_sens (const void *a, const void *b) { - const ucl_object_t *oa = *(const ucl_object_t **)a, - *ob = *(const ucl_object_t **)b; + const struct ucl_hash_elt *oa = (const struct ucl_hash_elt *)a, + *ob = (const struct ucl_hash_elt *)b; - if (oa->keylen == ob->keylen) { - return memcmp (oa->key, ob->key, oa->keylen); + if (oa->obj->keylen == ob->obj->keylen) { + return memcmp (oa->obj->key, ob->obj->key, oa->obj->keylen); } - return ((int)(oa->keylen)) - ob->keylen; + return ((int)(oa->obj->keylen)) - ob->obj->keylen; } void @@ -619,18 +611,18 @@ ucl_hash_sort (ucl_hash_t *hashlin, enum ucl_object_keys_sort_flags fl) { if (fl & UCL_SORT_KEYS_ICASE) { - qsort (hashlin->ar.a, hashlin->ar.n, sizeof (ucl_object_t *), - ucl_hash_cmp_icase); + DL_SORT(hashlin->head, ucl_hash_cmp_icase); } else { - qsort (hashlin->ar.a, hashlin->ar.n, sizeof (ucl_object_t *), - ucl_hash_cmp_case_sens); + DL_SORT(hashlin->head, ucl_hash_cmp_case_sens); } if (fl & UCL_SORT_KEYS_RECURSIVE) { - for (size_t i = 0; i < hashlin->ar.n; i ++) { - if (ucl_object_type (hashlin->ar.a[i]) == UCL_OBJECT) { - ucl_hash_sort (hashlin->ar.a[i]->value.ov, fl); + struct ucl_hash_elt *elt; + + DL_FOREACH(hashlin->head, elt) { + if (ucl_object_type (elt->obj) == UCL_OBJECT) { + ucl_hash_sort (elt->obj->value.ov, fl); } } } diff --git a/contrib/libucl/src/ucl_msgpack.c b/contrib/libucl/src/ucl_msgpack.c index 08e690a4728a..628ed2be993d 100644 --- a/contrib/libucl/src/ucl_msgpack.c +++ b/contrib/libucl/src/ucl_msgpack.c @@ -1246,8 +1246,8 @@ ucl_msgpack_consume (struct ucl_parser *parser) /* Empty container at the end */ if (len != 0) { ucl_create_err (&parser->err, - "invalid non-empty container at the end; len=%zu", - (size_t)len); + "invalid non-empty container at the end; len=%ju", + (uintmax_t)len); return false; } diff --git a/contrib/libucl/src/ucl_parser.c b/contrib/libucl/src/ucl_parser.c index 23f5bce3056f..6be16d12169c 100644 --- a/contrib/libucl/src/ucl_parser.c +++ b/contrib/libucl/src/ucl_parser.c @@ -47,6 +47,9 @@ struct ucl_parser_saved_state { */ #define ucl_chunk_skipc(chunk, p) \ do { \ + if (p == chunk->end) { \ + break; \ + } \ if (*(p) == '\n') { \ (chunk)->line ++; \ (chunk)->column = 0; \ @@ -176,7 +179,7 @@ start: if (!quoted) { if (*p == '*') { ucl_chunk_skipc (chunk, p); - if (*p == '/') { + if (chunk->remain > 0 && *p == '/') { comments_nested --; if (comments_nested == 0) { if (parser->flags & UCL_PARSER_SAVE_COMMENTS) { @@ -345,8 +348,9 @@ ucl_check_variable_safe (struct ucl_parser *parser, const char *ptr, size_t rema /* Call generic handler */ if (parser->var_handler (ptr, remain, &dst, &dstlen, &need_free, parser->var_data)) { - *out_len = dstlen; *found = true; + *out_len = dstlen; + if (need_free) { free (dst); } @@ -395,6 +399,9 @@ ucl_check_variable (struct ucl_parser *parser, const char *ptr, } p ++; } + if(p == end) { + (*out_len) ++; + } } else if (*ptr != '$') { /* Not count escaped dollar sign */ @@ -418,13 +425,14 @@ ucl_check_variable (struct ucl_parser *parser, const char *ptr, * Expand a single variable * @param parser * @param ptr - * @param remain + * @param in_len * @param dest + * @param out_len * @return */ static const char * ucl_expand_single_variable (struct ucl_parser *parser, const char *ptr, - size_t remain, unsigned char **dest) + size_t in_len, unsigned char **dest, size_t out_len) { unsigned char *d = *dest, *dst; const char *p = ptr + 1, *ret; @@ -435,7 +443,8 @@ ucl_expand_single_variable (struct ucl_parser *parser, const char *ptr, bool strict = false; ret = ptr + 1; - remain --; + /* For the $ sign */ + in_len --; if (*p == '$') { *d++ = *p++; @@ -444,39 +453,53 @@ ucl_expand_single_variable (struct ucl_parser *parser, const char *ptr, } else if (*p == '{') { p ++; + in_len --; strict = true; ret += 2; - remain -= 2; } LL_FOREACH (parser->variables, var) { - if (remain >= var->var_len) { + if (out_len >= var->value_len && in_len >= (var->var_len + (strict ? 1 : 0))) { if (memcmp (p, var->var, var->var_len) == 0) { - memcpy (d, var->value, var->value_len); - ret += var->var_len; - d += var->value_len; - found = true; - break; + if (!strict || p[var->var_len] == '}') { + memcpy (d, var->value, var->value_len); + ret += var->var_len; + d += var->value_len; + found = true; + break; + } } } } + if (!found) { if (strict && parser->var_handler != NULL) { - if (parser->var_handler (p, remain, &dst, &dstlen, &need_free, + dstlen = out_len; + + if (parser->var_handler (p, in_len, &dst, &dstlen, &need_free, parser->var_data)) { - memcpy (d, dst, dstlen); - ret += remain; - d += dstlen; - found = true; - if (need_free) { - free (dst); + if (dstlen > out_len) { + /* We do not have enough space! */ + if (need_free) { + free (dst); + } + } + else { + memcpy(d, dst, dstlen); + ret += in_len; + d += dstlen; + found = true; + + if (need_free) { + free(dst); + } } } } - /* Leave variable as is */ + /* Leave variable as is, in this case we use dest */ if (!found) { - if (strict) { + if (strict && out_len >= 2) { /* Copy '${' */ memcpy (d, ptr, 2); d += 2; @@ -506,7 +529,7 @@ ucl_expand_variable (struct ucl_parser *parser, unsigned char **dst, const char *src, size_t in_len) { const char *p, *end = src + in_len; - unsigned char *d; + unsigned char *d, *d_end; size_t out_len = 0; bool vars_found = false; @@ -517,7 +540,7 @@ ucl_expand_variable (struct ucl_parser *parser, unsigned char **dst, p = src; while (p != end) { - if (*p == '$') { + if (*p == '$' && p + 1 != end) { p = ucl_check_variable (parser, p + 1, end - p - 1, &out_len, &vars_found); } else { @@ -538,10 +561,11 @@ ucl_expand_variable (struct ucl_parser *parser, unsigned char **dst, } d = *dst; + d_end = d + out_len; p = src; - while (p != end) { - if (*p == '$') { - p = ucl_expand_single_variable (parser, p, end - p, &d); + while (p != end && d != d_end) { + if (*p == '$' && p + 1 != end) { + p = ucl_expand_single_variable (parser, p, end - p, &d, d_end - d); } else { *d++ = *p++; @@ -686,6 +710,8 @@ ucl_parser_add_container (ucl_object_t *obj, struct ucl_parser *parser, ucl_object_unref (obj); } + UCL_FREE(sizeof (struct ucl_stack), st); + return NULL; } @@ -722,13 +748,13 @@ ucl_maybe_parse_number (ucl_object_t *obj, const char *p = start, *c = start; char *endptr; bool got_dot = false, got_exp = false, need_double = false, - is_time = false, valid_start = false, is_hex = false, - is_neg = false; + is_time = false, valid_start = false, is_hex = false; + int is_neg = 0; double dv = 0; int64_t lv = 0; if (*p == '-') { - is_neg = true; + is_neg = 1; c ++; p ++; } @@ -744,6 +770,7 @@ ucl_maybe_parse_number (ucl_object_t *obj, is_hex = true; allow_double = false; c = p + 1; + p ++; } else if (allow_double) { if (p == c) { @@ -792,26 +819,46 @@ ucl_maybe_parse_number (ucl_object_t *obj, break; } } + else if (!allow_double && *p == '.') { + /* Unexpected dot */ + *pos = start; + return EINVAL; + } else { break; } } - if (!valid_start) { + if (!valid_start || p == c) { + *pos = start; + return EINVAL; + } + + char numbuf[128]; + + if ((size_t)(p - c + 1) >= sizeof(numbuf)) { *pos = start; return EINVAL; } + if (is_neg) { + numbuf[0] = '-'; + ucl_strlcpy (&numbuf[1], c, p - c + 1); + } + else { + ucl_strlcpy (numbuf, c, p - c + 1); + } + errno = 0; if (need_double) { - dv = strtod (c, &endptr); + dv = strtod (numbuf, &endptr); } else { if (is_hex) { - lv = strtoimax (c, &endptr, 16); + lv = strtoimax (numbuf, &endptr, 16); } else { - lv = strtoimax (c, &endptr, 10); + lv = strtoimax (numbuf, &endptr, 10); } } if (errno == ERANGE) { @@ -819,7 +866,15 @@ ucl_maybe_parse_number (ucl_object_t *obj, return ERANGE; } - /* Now check endptr */ + /* Now check endptr and move it from numbuf to the real ending */ + if (endptr != NULL) { + long shift = endptr - numbuf - is_neg; + endptr = (char *)c + shift; + } + if (endptr >= end) { + p = end; + goto set_obj; + } if (endptr == NULL || ucl_lex_is_atom_end (*endptr) || *endptr == '\0') { p = endptr; goto set_obj; @@ -849,6 +904,10 @@ ucl_maybe_parse_number (ucl_object_t *obj, dv *= ucl_lex_num_multiplier (*p, false); } p += 2; + if (end - p > 0 && !ucl_lex_is_atom_end (*p)) { + *pos = start; + return EINVAL; + } goto set_obj; } else if (number_bytes || (p[1] == 'b' || p[1] == 'B')) { @@ -859,6 +918,10 @@ ucl_maybe_parse_number (ucl_object_t *obj, } lv *= ucl_lex_num_multiplier (*p, true); p += 2; + if (end - p > 0 && !ucl_lex_is_atom_end (*p)) { + *pos = start; + return EINVAL; + } goto set_obj; } else if (ucl_lex_is_atom_end (p[1])) { @@ -883,6 +946,10 @@ ucl_maybe_parse_number (ucl_object_t *obj, is_time = true; dv *= 60.; p += 3; + if (end - p > 0 && !ucl_lex_is_atom_end (*p)) { + *pos = start; + return EINVAL; + } goto set_obj; } } @@ -895,6 +962,10 @@ ucl_maybe_parse_number (ucl_object_t *obj, lv *= ucl_lex_num_multiplier (*p, number_bytes); } p ++; + if (end - p > 0 && !ucl_lex_is_atom_end (*p)) { + *pos = start; + return EINVAL; + } goto set_obj; } break; @@ -943,7 +1014,7 @@ ucl_maybe_parse_number (ucl_object_t *obj, } else if (endptr == end) { /* Just a number at the end of chunk */ - p = endptr; + p = end; goto set_obj; } @@ -959,11 +1030,11 @@ set_obj: else { obj->type = UCL_TIME; } - obj->value.dv = is_neg ? (-dv) : dv; + obj->value.dv = dv; } else { obj->type = UCL_INT; - obj->value.iv = is_neg ? (-lv) : lv; + obj->value.iv = lv; } } *pos = p; @@ -1037,13 +1108,13 @@ ucl_lex_json_string (struct ucl_parser *parser, } else if (c == '\\') { ucl_chunk_skipc (chunk, p); - c = *p; if (p >= chunk->end) { ucl_set_err (parser, UCL_ESYNTAX, "unfinished escape character", &parser->err); return false; } - else if (ucl_test_character (c, UCL_CHARACTER_ESCAPE)) { + c = *p; + if (ucl_test_character (c, UCL_CHARACTER_ESCAPE)) { if (c == 'u') { ucl_chunk_skipc (chunk, p); for (i = 0; i < 4 && p < chunk->end; i ++) { @@ -1289,24 +1360,20 @@ ucl_parser_process_object_element (struct ucl_parser *parser, ucl_object_t *nobj */ static bool ucl_parse_key (struct ucl_parser *parser, struct ucl_chunk *chunk, - bool *next_key, bool *end_of_object) + bool *next_key, bool *end_of_object, bool *got_content) { const unsigned char *p, *c = NULL, *end, *t; const char *key = NULL; bool got_quote = false, got_eq = false, got_semicolon = false, need_unescape = false, ucl_escape = false, var_expand = false, - got_content = false, got_sep = false; + got_sep = false; ucl_object_t *nobj; ssize_t keylen; p = chunk->pos; - if (*p == '.') { - /* It is macro actually */ - if (!(parser->flags & UCL_PARSER_DISABLE_MACRO)) { - ucl_chunk_skipc (chunk, p); - } - + if (*p == '.' && !(parser->flags & UCL_PARSER_DISABLE_MACRO)) { + ucl_chunk_skipc (chunk, p); parser->prev_state = parser->state; parser->state = UCL_STATE_MACRO_NAME; *end_of_object = false; @@ -1330,13 +1397,13 @@ ucl_parse_key (struct ucl_parser *parser, struct ucl_chunk *chunk, /* The first symbol */ c = p; ucl_chunk_skipc (chunk, p); - got_content = true; + *got_content = true; } else if (*p == '"') { /* JSON style key */ c = p + 1; got_quote = true; - got_content = true; + *got_content = true; ucl_chunk_skipc (chunk, p); } else if (*p == '}') { @@ -1344,7 +1411,7 @@ ucl_parse_key (struct ucl_parser *parser, struct ucl_chunk *chunk, *end_of_object = true; return true; } - else if (*p == '.') { + else if (*p == '.' && !(parser->flags & UCL_PARSER_DISABLE_MACRO)) { ucl_chunk_skipc (chunk, p); parser->prev_state = parser->state; parser->state = UCL_STATE_MACRO_NAME; @@ -1361,7 +1428,7 @@ ucl_parse_key (struct ucl_parser *parser, struct ucl_chunk *chunk, /* Parse the body of a key */ if (!got_quote) { if (ucl_test_character (*p, UCL_CHARACTER_KEY)) { - got_content = true; + *got_content = true; ucl_chunk_skipc (chunk, p); } else if (ucl_test_character (*p, UCL_CHARACTER_KEY_SEP)) { @@ -1387,11 +1454,11 @@ ucl_parse_key (struct ucl_parser *parser, struct ucl_chunk *chunk, } } - if (p >= chunk->end && got_content) { + if (p >= chunk->end && *got_content) { ucl_set_err (parser, UCL_ESYNTAX, "unfinished key", &parser->err); return false; } - else if (!got_content) { + else if (!*got_content) { return true; } *end_of_object = false; @@ -1752,6 +1819,9 @@ ucl_parse_value (struct ucl_parser *parser, struct ucl_chunk *chunk) case '{': obj = ucl_parser_get_container (parser); if (obj == NULL) { + parser->state = UCL_STATE_ERROR; + ucl_set_err(parser, UCL_ESYNTAX, "object value must be a part of an object", + &parser->err); return false; } /* We have a new object */ @@ -1773,6 +1843,9 @@ ucl_parse_value (struct ucl_parser *parser, struct ucl_chunk *chunk) case '[': obj = ucl_parser_get_container (parser); if (obj == NULL) { + parser->state = UCL_STATE_ERROR; + ucl_set_err(parser, UCL_ESYNTAX, "array value must be a part of an object", + &parser->err); return false; } /* We have a new array */ @@ -1804,6 +1877,12 @@ ucl_parse_value (struct ucl_parser *parser, struct ucl_chunk *chunk) break; case '<': obj = ucl_parser_get_container (parser); + if (obj == NULL) { + parser->state = UCL_STATE_ERROR; + ucl_set_err(parser, UCL_ESYNTAX, "multiline value must be a part of an object", + &parser->err); + return false; + } /* We have something like multiline value, which must be <<[A-Z]+\n */ if (chunk->end - p > 3) { if (memcmp (p, "<<", 2) == 0) { @@ -1812,6 +1891,11 @@ ucl_parse_value (struct ucl_parser *parser, struct ucl_chunk *chunk) while (p < chunk->end && *p >= 'A' && *p <= 'Z') { p ++; } + if(p == chunk->end) { + ucl_set_err (parser, UCL_ESYNTAX, + "unterminated multiline value", &parser->err); + return false; + } if (*p =='\n') { /* Set chunk positions and start multiline parsing */ chunk->remain -= p - c + 1; @@ -1850,6 +1934,13 @@ parse_string: obj = ucl_parser_get_container (parser); } + if (obj == NULL) { + parser->state = UCL_STATE_ERROR; + ucl_set_err(parser, UCL_ESYNTAX, "value must be a part of an object", + &parser->err); + return false; + } + /* Parse atom */ if (ucl_test_character (*p, UCL_CHARACTER_VALUE_DIGIT_START)) { if (!ucl_lex_number (parser, chunk, obj)) { @@ -2339,7 +2430,7 @@ ucl_state_machine (struct ucl_parser *parser) unsigned char *macro_escaped; size_t macro_len = 0; struct ucl_macro *macro = NULL; - bool next_key = false, end_of_object = false, ret; + bool next_key = false, end_of_object = false, got_content = false, ret; if (parser->top_obj == NULL) { parser->state = UCL_STATE_INIT; @@ -2428,7 +2519,10 @@ ucl_state_machine (struct ucl_parser *parser) parser->state = UCL_STATE_ERROR; return false; } - if (!ucl_parse_key (parser, chunk, &next_key, &end_of_object)) { + + got_content = false; + + if (!ucl_parse_key (parser, chunk, &next_key, &end_of_object, &got_content)) { parser->prev_state = parser->state; parser->state = UCL_STATE_ERROR; return false; @@ -2451,7 +2545,8 @@ ucl_state_machine (struct ucl_parser *parser) return false; } } - else { + else if (got_content) { + /* Do not switch state if we have not read any content */ parser->state = UCL_STATE_VALUE; } } @@ -2617,6 +2712,9 @@ ucl_state_machine (struct ucl_parser *parser) return false; } break; + case UCL_STATE_ERROR: + /* Already in the error state */ + return false; default: ucl_set_err (parser, UCL_EINTERNAL, "internal error: parser is in an unknown state", &parser->err); @@ -2889,7 +2987,9 @@ ucl_parser_add_chunk_full (struct ucl_parser *parser, const unsigned char *data, if (!special_handler->handler (parser, data, len, &ndata, &nlen, special_handler->user_data)) { + UCL_FREE(sizeof (struct ucl_chunk), chunk); ucl_create_err (&parser->err, "call for external handler failed"); + return false; } @@ -2909,7 +3009,7 @@ ucl_parser_add_chunk_full (struct ucl_parser *parser, const unsigned char *data, if (parse_type == UCL_PARSE_AUTO && len > 0) { /* We need to detect parse type by the first symbol */ - if ((*data & 0x80) == 0x80 && (*data >= 0xdc && *data <= 0xdf)) { + if ((*data & 0x80) == 0x80) { parse_type = UCL_PARSE_MSGPACK; } else if (*data == '(') { diff --git a/contrib/libucl/src/ucl_schema.c b/contrib/libucl/src/ucl_schema.c index 68f01187e375..f4ec0ed3284a 100644 --- a/contrib/libucl/src/ucl_schema.c +++ b/contrib/libucl/src/ucl_schema.c @@ -39,6 +39,7 @@ #ifdef HAVE_MATH_H #include <math.h> #endif +#include <inttypes.h> static bool ucl_schema_validate (const ucl_object_t *schema, const ucl_object_t *obj, bool try_array, diff --git a/contrib/libucl/src/ucl_util.c b/contrib/libucl/src/ucl_util.c index b00a34787e5a..8f97c20db503 100644 --- a/contrib/libucl/src/ucl_util.c +++ b/contrib/libucl/src/ucl_util.c @@ -67,7 +67,7 @@ typedef kvec_t(ucl_object_t *) ucl_array_t; #include <fetch.h> #endif -#if defined(_MSC_VER) +#if defined(_WIN32) #include <windows.h> #include <io.h> #include <direct.h> @@ -889,44 +889,49 @@ ucl_fetch_file (const unsigned char *filename, unsigned char **buf, size_t *bufl { int fd; struct stat st; + if ((fd = open (filename, O_RDONLY)) == -1) { + ucl_create_err (err, "cannot open file %s: %s", + filename, strerror (errno)); + return false; + } - if (stat (filename, &st) == -1) { + if (fstat (fd, &st) == -1) { if (must_exist || errno == EPERM) { ucl_create_err (err, "cannot stat file %s: %s", filename, strerror (errno)); } + close (fd); + return false; } if (!S_ISREG (st.st_mode)) { if (must_exist) { ucl_create_err (err, "file %s is not a regular file", filename); } + close (fd); return false; } + if (st.st_size == 0) { /* Do not map empty files */ *buf = NULL; *buflen = 0; } else { - if ((fd = open (filename, O_RDONLY)) == -1) { - ucl_create_err (err, "cannot open file %s: %s", - filename, strerror (errno)); - return false; - } - if ((*buf = ucl_mmap (NULL, st.st_size, PROT_READ, MAP_SHARED, fd, 0)) == MAP_FAILED) { - close (fd); - ucl_create_err (err, "cannot mmap file %s: %s", - filename, strerror (errno)); + if ((*buf = ucl_mmap(NULL, st.st_size, PROT_READ, MAP_SHARED, fd, 0)) == MAP_FAILED) { + close(fd); + ucl_create_err(err, "cannot mmap file %s: %s", + filename, strerror(errno)); *buf = NULL; return false; } *buflen = st.st_size; - close (fd); } + close (fd); + return true; } @@ -1017,6 +1022,9 @@ ucl_include_url (const unsigned char *data, size_t len, snprintf (urlbuf, sizeof (urlbuf), "%.*s", (int)len, data); if (!ucl_fetch_url (urlbuf, &buf, &buflen, &parser->err, params->must_exist)) { + if (!params->must_exist) { + ucl_parser_clear_error (parser); + } return !params->must_exist; } @@ -1092,6 +1100,11 @@ ucl_include_file_single (const unsigned char *data, size_t len, ucl_hash_t *container = NULL; struct ucl_stack *st = NULL; + if (parser->state == UCL_STATE_ERROR) { + /* Return immediately if we are in the error state... */ + return false; + } + snprintf (filebuf, sizeof (filebuf), "%.*s", (int)len, data); if (ucl_realpath (filebuf, realbuf) == NULL) { if (params->soft_fail) { @@ -1128,6 +1141,8 @@ ucl_include_file_single (const unsigned char *data, size_t len, return false; } + ucl_parser_clear_error (parser); + return true; } @@ -1138,6 +1153,10 @@ ucl_include_file_single (const unsigned char *data, size_t len, /* We need to check signature first */ snprintf (filebuf, sizeof (filebuf), "%s.sig", realbuf); if (!ucl_fetch_file (filebuf, &sigbuf, &siglen, &parser->err, true)) { + if (buf) { + ucl_munmap (buf, buflen); + } + return false; } if (!ucl_sig_check (buf, buflen, sigbuf, siglen, parser)) { @@ -1147,8 +1166,13 @@ ucl_include_file_single (const unsigned char *data, size_t len, if (sigbuf) { ucl_munmap (sigbuf, siglen); } + if (buf) { + ucl_munmap (buf, buflen); + } + return false; } + if (sigbuf) { ucl_munmap (sigbuf, siglen); } @@ -1257,6 +1281,8 @@ ucl_include_file_single (const unsigned char *data, size_t len, ucl_munmap (buf, buflen); } + ucl_object_unref (new_obj); + return false; } nest_obj->prev = nest_obj; @@ -1576,11 +1602,6 @@ ucl_include_common (const unsigned char *data, size_t len, else if (param->type == UCL_INT) { if (strncmp (param->key, "priority", param->keylen) == 0) { params.priority = ucl_object_toint (param); - if (params.priority > UCL_PRIORITY_MAX) { - ucl_create_err (&parser->err, "Invalid priority value in macro: %d", - params.priority); - return false; - } } } } @@ -1719,9 +1740,8 @@ ucl_priority_handler (const unsigned char *data, size_t len, if (len > 0) { value = malloc(len + 1); ucl_strlcpy(value, (const char *)data, len + 1); - errno = 0; - priority = strtoul(value, &leftover, 10); - if (errno != 0 || *leftover != '\0' || priority > UCL_PRIORITY_MAX) { + priority = strtol(value, &leftover, 10); + if (*leftover != '\0') { ucl_create_err (&parser->err, "Invalid priority value in macro: %s", value); free(value); @@ -1842,6 +1862,10 @@ ucl_load_handler (const unsigned char *data, size_t len, !try_load)) { free (load_file); + if (try_load) { + ucl_parser_clear_error (parser); + } + return (try_load || false); } @@ -1919,7 +1943,7 @@ ucl_inherit_handler (const unsigned char *data, size_t len, /* Some sanity checks */ if (parent == NULL || ucl_object_type (parent) != UCL_OBJECT) { - ucl_create_err (&parser->err, "Unable to find inherited object %*.s", + ucl_create_err (&parser->err, "Unable to find inherited object %.*s", (int)len, data); return false; } @@ -2177,7 +2201,7 @@ ucl_strnstr (const char *s, const char *find, int len) mlen = strlen (find); do { do { - if ((sc = *s++) == 0 || len-- == 0) + if ((sc = *s++) == 0 || len-- < mlen) return (NULL); } while (sc != c); } while (strncmp (s, find, mlen) != 0); @@ -2596,6 +2620,7 @@ ucl_object_merge (ucl_object_t *top, ucl_object_t *elt, bool copy) if (!ucl_object_merge (found, cp, copy)) { return false; } + ucl_object_unref (cp); } else { ucl_hash_replace (top->value.ov, found, cp); @@ -2627,6 +2652,7 @@ ucl_object_merge (ucl_object_t *top, ucl_object_t *elt, bool copy) if (!ucl_object_merge (found, cp, copy)) { return false; } + ucl_object_unref (cp); } else { ucl_hash_replace (top->value.ov, found, cp); @@ -3068,13 +3094,13 @@ ucl_object_type (const ucl_object_t *obj) ucl_object_t* ucl_object_fromstring (const char *str) { - return ucl_object_fromstring_common (str, 0, UCL_STRING_ESCAPE); + return ucl_object_fromstring_common (str, 0, UCL_STRING_RAW); } ucl_object_t * ucl_object_fromlstring (const char *str, size_t len) { - return ucl_object_fromstring_common (str, len, UCL_STRING_ESCAPE); + return ucl_object_fromstring_common (str, len, UCL_STRING_RAW); } ucl_object_t * @@ -3594,9 +3620,11 @@ ucl_object_copy_internal (const ucl_object_t *other, bool allow_array) /* deep copy of values stored */ if (other->trash_stack[UCL_TRASH_KEY] != NULL) { - new->trash_stack[UCL_TRASH_KEY] = - strdup (other->trash_stack[UCL_TRASH_KEY]); + new->trash_stack[UCL_TRASH_KEY] = NULL; if (other->key == (const char *)other->trash_stack[UCL_TRASH_KEY]) { + new->trash_stack[UCL_TRASH_KEY] = malloc(other->keylen + 1); + memcpy(new->trash_stack[UCL_TRASH_KEY], other->trash_stack[UCL_TRASH_KEY], other->keylen); + new->trash_stack[UCL_TRASH_KEY][other->keylen] = '\0'; new->key = new->trash_stack[UCL_TRASH_KEY]; } } @@ -3666,13 +3694,6 @@ ucl_object_compare (const ucl_object_t *o1, const ucl_object_t *o2) ucl_object_iter_t iter = NULL; int ret = 0; - // Must check for NULL or code will segfault - if ((o1 == NULL) || (o2 == NULL)) - { - // The only way this could be true is of both are NULL - return (o1 == NULL) && (o2 == NULL); - } - if (o1->type != o2->type) { return (o1->type) - (o2->type); } diff --git a/contrib/libucl/stamp-h.in b/contrib/libucl/stamp-h.in deleted file mode 100644 index 9788f70238c9..000000000000 --- a/contrib/libucl/stamp-h.in +++ /dev/null @@ -1 +0,0 @@ -timestamp diff --git a/contrib/libucl/tests/.gitignore b/contrib/libucl/tests/.gitignore new file mode 100644 index 000000000000..464482434f22 --- /dev/null +++ b/contrib/libucl/tests/.gitignore @@ -0,0 +1,10 @@ +*.log +*.trs +*.plist + +test_basic +test_generate +test_msgpack +test_schema +test_speed +test_streamline diff --git a/contrib/libucl/tests/Makefile.am b/contrib/libucl/tests/Makefile.am deleted file mode 100644 index 055eb8bd85b0..000000000000 --- a/contrib/libucl/tests/Makefile.am +++ /dev/null @@ -1,45 +0,0 @@ -EXTRA_DIST = $(TESTS) basic schema generate.res \ - streamline.res rcl_test.json.xz - -TESTS = basic.test \ - generate.test \ - schema.test \ - msgpack.test \ - speed.test \ - msgpack.test -TESTS_ENVIRONMENT = $(SH) \ - TEST_DIR=$(top_srcdir)/tests \ - TEST_OUT_DIR=$(top_builddir)/tests \ - TEST_BINARY_DIR=$(top_builddir)/tests - -common_test_cflags = -I$(top_srcdir)/include \ - -I$(top_srcdir)/src \ - -I$(top_srcdir)/uthash -common_test_ldadd = $(top_builddir)/src/libucl.la - -test_basic_SOURCES = test_basic.c -test_basic_LDADD = $(common_test_ldadd) -test_basic_CFLAGS = $(common_test_cflags) - -test_speed_SOURCES = test_speed.c -test_speed_LDADD = $(common_test_ldadd) -test_speed_CFLAGS = $(common_test_cflags) - -test_generate_SOURCES = test_generate.c -test_generate_LDADD = $(common_test_ldadd) -test_generate_CFLAGS = $(common_test_cflags) - -test_schema_SOURCES = test_schema.c -test_schema_LDADD = $(common_test_ldadd) -test_schema_CFLAGS = $(common_test_cflags) - -test_streamline_SOURCES = test_streamline.c -test_streamline_LDADD = $(common_test_ldadd) -test_streamline_CFLAGS = $(common_test_cflags) - -test_msgpack_SOURCES = test_msgpack.c -test_msgpack_LDADD = $(common_test_ldadd) -test_msgpack_CFLAGS = $(common_test_cflags) - -check_PROGRAMS = test_basic test_speed test_generate test_schema test_streamline \ - test_msgpack
\ No newline at end of file diff --git a/contrib/libucl/tests/schema/definitions.json b/contrib/libucl/tests/schema/definitions.json deleted file mode 100644 index 1ab9b2163c44..000000000000 --- a/contrib/libucl/tests/schema/definitions.json +++ /dev/null @@ -1,32 +0,0 @@ -[ - { - "description": "valid definition", - "schema": {"$ref": "http://highsecure.ru/ucl-schema/schema#"}, - "tests": [ - { - "description": "valid definition schema", - "data": { - "definitions": { - "foo": {"type": "integer"} - } - }, - "valid": true - } - ] - }, - { - "description": "invalid definition", - "schema": {"$ref": "http://highsecure.ru/ucl-schema/schema#"}, - "tests": [ - { - "description": "invalid definition schema", - "data": { - "definitions": { - "foo": {"type": 1} - } - }, - "valid": false - } - ] - } -] diff --git a/contrib/libucl/tests/schema/ref.json b/contrib/libucl/tests/schema/ref.json index 1767769cd845..d8214bc2b30c 100644 --- a/contrib/libucl/tests/schema/ref.json +++ b/contrib/libucl/tests/schema/ref.json @@ -124,21 +124,5 @@ "valid": false } ] - }, - { - "description": "remote ref, containing refs itself", - "schema": {"$ref": "http://highsecure.ru/ucl-schema/schema#"}, - "tests": [ - { - "description": "remote ref valid", - "data": {"minLength": 1}, - "valid": true - }, - { - "description": "remote ref invalid", - "data": {"minLength": -1}, - "valid": false - } - ] } ] diff --git a/contrib/libucl/tests/schema/refRemote.json b/contrib/libucl/tests/schema/refRemote.json deleted file mode 100644 index 067c666b0ec8..000000000000 --- a/contrib/libucl/tests/schema/refRemote.json +++ /dev/null @@ -1,76 +0,0 @@ -[ - { - "description": "remote ref", - "schema": {"$ref": "http://highsecure.ru/ucl-schema/remotes/integer.json"}, - "tests": [ - { - "description": "remote ref valid", - "data": 1, - "valid": true - }, - { - "description": "remote ref invalid", - "data": "a", - "valid": false - } - ] - }, - { - "description": "fragment within remote ref", - "schema": {"$ref": "http://highsecure.ru/ucl-schema/remotes/subSchemas.json#/integer"}, - "tests": [ - { - "description": "remote fragment valid", - "data": 1, - "valid": true - }, - { - "description": "remote fragment invalid", - "data": "a", - "valid": false - } - ] - }, - { - "description": "ref within remote ref", - "schema": { - "$ref": "http://highsecure.ru/ucl-schema/remotes/subSchemas.json#/refToInteger" - }, - "tests": [ - { - "description": "ref within ref valid", - "data": 1, - "valid": true - }, - { - "description": "ref within ref invalid", - "data": "a", - "valid": false - } - ] - } -/* - { - "description": "change resolution scope", - "schema": { - "id": "http://highsecure.ru/ucl-schema/remotes/", - "items": { - "id": "folder/", - "items": {"$ref": "folderInteger.json"} - } - }, - "tests": [ - { - "description": "changed scope ref valid", - "data": [[1]], - "valid": true - }, - { - "description": "changed scope ref invalid", - "data": [["a"]], - "valid": false - } - ] - } -*/ -] diff --git a/contrib/libucl/tests/test_speed.c b/contrib/libucl/tests/test_speed.c index 56f2e5abc6c7..51476c94940b 100644 --- a/contrib/libucl/tests/test_speed.c +++ b/contrib/libucl/tests/test_speed.c @@ -44,7 +44,7 @@ get_ticks (void) { double res; -#ifdef __APPLE__ +#if defined(__APPLE__) && defined(HAVE_MACH_MACH_TIME_H) res = mach_absolute_time () / 1000000000.; #else struct timespec ts; diff --git a/contrib/libucl/tests/test_streamline.c b/contrib/libucl/tests/test_streamline.c index 4c56c4cdcffd..37fe14f9fb97 100644 --- a/contrib/libucl/tests/test_streamline.c +++ b/contrib/libucl/tests/test_streamline.c @@ -26,6 +26,10 @@ #include <assert.h> #include "ucl.h" +#include <sys/types.h> +#include <fcntl.h> +#include <unistd.h> + int main (int argc, char **argv) { @@ -34,7 +38,28 @@ main (int argc, char **argv) const char *fname_out = NULL; struct ucl_emitter_context *ctx; struct ucl_emitter_functions *f; - int ret = 0; + int ret = 0, opt, json = 0, compact = 0, yaml = 0; + + while ((opt = getopt(argc, argv, "jcy")) != -1) { + switch (opt) { + case 'j': + json = 1; + break; + case 'c': + compact = 1; + break; + case 'y': + yaml = 1; + break; + default: /* '?' */ + fprintf (stderr, "Usage: %s [-jcy] [out]\n", + argv[0]); + exit (EXIT_FAILURE); + } + } + + argc -= optind; + argv += optind; switch (argc) { case 2: @@ -63,7 +88,21 @@ main (int argc, char **argv) ucl_object_insert_key (obj, cur, "key3", 0, false); f = ucl_object_emit_file_funcs (out); - ctx = ucl_object_emit_streamline_new (obj, UCL_EMIT_CONFIG, f); + + if (yaml) { + ctx = ucl_object_emit_streamline_new (obj, UCL_EMIT_YAML, f); + } + else if (json) { + if (compact) { + ctx = ucl_object_emit_streamline_new (obj, UCL_EMIT_JSON_COMPACT, f); + } + else { + ctx = ucl_object_emit_streamline_new (obj, UCL_EMIT_JSON, f); + } + } + else { + ctx = ucl_object_emit_streamline_new (obj, UCL_EMIT_CONFIG, f); + } assert (ctx != NULL); diff --git a/contrib/libucl/uthash/utlist.h b/contrib/libucl/uthash/utlist.h index c82dd916e2ed..7cda1ca0ecac 100644 --- a/contrib/libucl/uthash/utlist.h +++ b/contrib/libucl/uthash/utlist.h @@ -1,5 +1,5 @@ /* -Copyright (c) 2007-2013, Troy D. Hanson http://troydhanson.github.com/uthash/ +Copyright (c) 2007-2022, Troy D. Hanson https://troydhanson.github.io/uthash/ All rights reserved. Redistribution and use in source and binary forms, with or without @@ -24,11 +24,11 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef UTLIST_H #define UTLIST_H -#define UTLIST_VERSION 1.9.8 +#define UTLIST_VERSION 2.3.0 #include <assert.h> -/* +/* * This file contains macros to manipulate singly and doubly-linked lists. * * 1. LL_ macros: singly-linked lists. @@ -38,7 +38,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * To use singly-linked lists, your structure must have a "next" pointer. * To use doubly-linked lists, your structure must "prev" and "next" pointers. * Either way, the pointer to the head of the list must be initialized to NULL. - * + * * ----------------.EXAMPLE ------------------------- * struct item { * int id; @@ -61,41 +61,46 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. /* These macros use decltype or the earlier __typeof GNU extension. As decltype is only available in newer compilers (VS2010 or gcc 4.3+ - when compiling c++ code), this code uses whatever method is needed + when compiling c++ source) this code uses whatever method is needed or, for VS2008 where neither is available, uses casting workarounds. */ -#ifdef _MSC_VER /* MS compiler */ +#if !defined(LDECLTYPE) && !defined(NO_DECLTYPE) +#if defined(_MSC_VER) /* MS compiler */ #if _MSC_VER >= 1600 && defined(__cplusplus) /* VS2010 or newer in C++ mode */ #define LDECLTYPE(x) decltype(x) -#else /* VS2008 or older (or VS2010 in C mode) */ +#else /* VS2008 or older (or VS2010 in C mode) */ #define NO_DECLTYPE -#define LDECLTYPE(x) char* #endif -#elif defined(__ICCARM__) +#elif defined(__MCST__) /* Elbrus C Compiler */ +#define LDECLTYPE(x) __typeof(x) +#elif defined(__BORLANDC__) || defined(__ICCARM__) || defined(__LCC__) || defined(__WATCOMC__) #define NO_DECLTYPE -#define LDECLTYPE(x) char* -#else /* GNU, Sun and other compilers */ +#else /* GNU, Sun and other compilers */ #define LDECLTYPE(x) __typeof(x) #endif +#endif /* for VS2008 we use some workarounds to get around the lack of decltype, * namely, we always reassign our tmp variable to the list head if we need * to dereference its prev/next pointers, and save/restore the real head.*/ #ifdef NO_DECLTYPE -#define _SV(elt,list) _tmp = (char*)(list); {char **_alias = (char**)&(list); *_alias = (elt); } -#define _NEXT(elt,list,next) ((char*)((list)->next)) -#define _NEXTASGN(elt,list,to,next) { char **_alias = (char**)&((list)->next); *_alias=(char*)(to); } -/* #define _PREV(elt,list,prev) ((char*)((list)->prev)) */ -#define _PREVASGN(elt,list,to,prev) { char **_alias = (char**)&((list)->prev); *_alias=(char*)(to); } -#define _RS(list) { char **_alias = (char**)&(list); *_alias=_tmp; } -#define _CASTASGN(a,b) { char **_alias = (char**)&(a); *_alias=(char*)(b); } -#else -#define _SV(elt,list) -#define _NEXT(elt,list,next) ((elt)->next) -#define _NEXTASGN(elt,list,to,next) ((elt)->next)=(to) -/* #define _PREV(elt,list,prev) ((elt)->prev) */ -#define _PREVASGN(elt,list,to,prev) ((elt)->prev)=(to) -#define _RS(list) -#define _CASTASGN(a,b) (a)=(b) +#define IF_NO_DECLTYPE(x) x +#define LDECLTYPE(x) char* +#define UTLIST_SV(elt,list) _tmp = (char*)(list); {char **_alias = (char**)&(list); *_alias = (elt); } +#define UTLIST_NEXT(elt,list,next) ((char*)((list)->next)) +#define UTLIST_NEXTASGN(elt,list,to,next) { char **_alias = (char**)&((list)->next); *_alias=(char*)(to); } +/* #define UTLIST_PREV(elt,list,prev) ((char*)((list)->prev)) */ +#define UTLIST_PREVASGN(elt,list,to,prev) { char **_alias = (char**)&((list)->prev); *_alias=(char*)(to); } +#define UTLIST_RS(list) { char **_alias = (char**)&(list); *_alias=_tmp; } +#define UTLIST_CASTASGN(a,b) { char **_alias = (char**)&(a); *_alias=(char*)(b); } +#else +#define IF_NO_DECLTYPE(x) +#define UTLIST_SV(elt,list) +#define UTLIST_NEXT(elt,list,next) ((elt)->next) +#define UTLIST_NEXTASGN(elt,list,to,next) ((elt)->next)=(to) +/* #define UTLIST_PREV(elt,list,prev) ((elt)->prev) */ +#define UTLIST_PREVASGN(elt,list,to,prev) ((elt)->prev)=(to) +#define UTLIST_RS(list) +#define UTLIST_CASTASGN(a,b) (a)=(b) #endif /****************************************************************************** @@ -111,13 +116,14 @@ do { LDECLTYPE(list) _ls_q; \ LDECLTYPE(list) _ls_e; \ LDECLTYPE(list) _ls_tail; \ + IF_NO_DECLTYPE(LDECLTYPE(list) _tmp;) \ int _ls_insize, _ls_nmerges, _ls_psize, _ls_qsize, _ls_i, _ls_looping; \ if (list) { \ _ls_insize = 1; \ _ls_looping = 1; \ while (_ls_looping) { \ - _CASTASGN(_ls_p,list); \ - list = NULL; \ + UTLIST_CASTASGN(_ls_p,list); \ + (list) = NULL; \ _ls_tail = NULL; \ _ls_nmerges = 0; \ while (_ls_p) { \ @@ -126,35 +132,35 @@ do { _ls_psize = 0; \ for (_ls_i = 0; _ls_i < _ls_insize; _ls_i++) { \ _ls_psize++; \ - _SV(_ls_q,list); _ls_q = _NEXT(_ls_q,list,next); _RS(list); \ + UTLIST_SV(_ls_q,list); _ls_q = UTLIST_NEXT(_ls_q,list,next); UTLIST_RS(list); \ if (!_ls_q) break; \ } \ _ls_qsize = _ls_insize; \ while (_ls_psize > 0 || (_ls_qsize > 0 && _ls_q)) { \ if (_ls_psize == 0) { \ - _ls_e = _ls_q; _SV(_ls_q,list); _ls_q = \ - _NEXT(_ls_q,list,next); _RS(list); _ls_qsize--; \ + _ls_e = _ls_q; UTLIST_SV(_ls_q,list); _ls_q = \ + UTLIST_NEXT(_ls_q,list,next); UTLIST_RS(list); _ls_qsize--; \ } else if (_ls_qsize == 0 || !_ls_q) { \ - _ls_e = _ls_p; _SV(_ls_p,list); _ls_p = \ - _NEXT(_ls_p,list,next); _RS(list); _ls_psize--; \ + _ls_e = _ls_p; UTLIST_SV(_ls_p,list); _ls_p = \ + UTLIST_NEXT(_ls_p,list,next); UTLIST_RS(list); _ls_psize--; \ } else if (cmp(_ls_p,_ls_q) <= 0) { \ - _ls_e = _ls_p; _SV(_ls_p,list); _ls_p = \ - _NEXT(_ls_p,list,next); _RS(list); _ls_psize--; \ + _ls_e = _ls_p; UTLIST_SV(_ls_p,list); _ls_p = \ + UTLIST_NEXT(_ls_p,list,next); UTLIST_RS(list); _ls_psize--; \ } else { \ - _ls_e = _ls_q; _SV(_ls_q,list); _ls_q = \ - _NEXT(_ls_q,list,next); _RS(list); _ls_qsize--; \ + _ls_e = _ls_q; UTLIST_SV(_ls_q,list); _ls_q = \ + UTLIST_NEXT(_ls_q,list,next); UTLIST_RS(list); _ls_qsize--; \ } \ if (_ls_tail) { \ - _SV(_ls_tail,list); _NEXTASGN(_ls_tail,list,_ls_e,next); _RS(list); \ + UTLIST_SV(_ls_tail,list); UTLIST_NEXTASGN(_ls_tail,list,_ls_e,next); UTLIST_RS(list); \ } else { \ - _CASTASGN(list,_ls_e); \ + UTLIST_CASTASGN(list,_ls_e); \ } \ _ls_tail = _ls_e; \ } \ _ls_p = _ls_q; \ } \ if (_ls_tail) { \ - _SV(_ls_tail,list); _NEXTASGN(_ls_tail,list,NULL,next); _RS(list); \ + UTLIST_SV(_ls_tail,list); UTLIST_NEXTASGN(_ls_tail,list,NULL,next); UTLIST_RS(list); \ } \ if (_ls_nmerges <= 1) { \ _ls_looping=0; \ @@ -174,13 +180,14 @@ do { LDECLTYPE(list) _ls_q; \ LDECLTYPE(list) _ls_e; \ LDECLTYPE(list) _ls_tail; \ + IF_NO_DECLTYPE(LDECLTYPE(list) _tmp;) \ int _ls_insize, _ls_nmerges, _ls_psize, _ls_qsize, _ls_i, _ls_looping; \ if (list) { \ _ls_insize = 1; \ _ls_looping = 1; \ while (_ls_looping) { \ - _CASTASGN(_ls_p,list); \ - list = NULL; \ + UTLIST_CASTASGN(_ls_p,list); \ + (list) = NULL; \ _ls_tail = NULL; \ _ls_nmerges = 0; \ while (_ls_p) { \ @@ -189,36 +196,36 @@ do { _ls_psize = 0; \ for (_ls_i = 0; _ls_i < _ls_insize; _ls_i++) { \ _ls_psize++; \ - _SV(_ls_q,list); _ls_q = _NEXT(_ls_q,list,next); _RS(list); \ + UTLIST_SV(_ls_q,list); _ls_q = UTLIST_NEXT(_ls_q,list,next); UTLIST_RS(list); \ if (!_ls_q) break; \ } \ _ls_qsize = _ls_insize; \ - while (_ls_psize > 0 || (_ls_qsize > 0 && _ls_q)) { \ + while ((_ls_psize > 0) || ((_ls_qsize > 0) && _ls_q)) { \ if (_ls_psize == 0) { \ - _ls_e = _ls_q; _SV(_ls_q,list); _ls_q = \ - _NEXT(_ls_q,list,next); _RS(list); _ls_qsize--; \ - } else if (_ls_qsize == 0 || !_ls_q) { \ - _ls_e = _ls_p; _SV(_ls_p,list); _ls_p = \ - _NEXT(_ls_p,list,next); _RS(list); _ls_psize--; \ + _ls_e = _ls_q; UTLIST_SV(_ls_q,list); _ls_q = \ + UTLIST_NEXT(_ls_q,list,next); UTLIST_RS(list); _ls_qsize--; \ + } else if ((_ls_qsize == 0) || (!_ls_q)) { \ + _ls_e = _ls_p; UTLIST_SV(_ls_p,list); _ls_p = \ + UTLIST_NEXT(_ls_p,list,next); UTLIST_RS(list); _ls_psize--; \ } else if (cmp(_ls_p,_ls_q) <= 0) { \ - _ls_e = _ls_p; _SV(_ls_p,list); _ls_p = \ - _NEXT(_ls_p,list,next); _RS(list); _ls_psize--; \ + _ls_e = _ls_p; UTLIST_SV(_ls_p,list); _ls_p = \ + UTLIST_NEXT(_ls_p,list,next); UTLIST_RS(list); _ls_psize--; \ } else { \ - _ls_e = _ls_q; _SV(_ls_q,list); _ls_q = \ - _NEXT(_ls_q,list,next); _RS(list); _ls_qsize--; \ + _ls_e = _ls_q; UTLIST_SV(_ls_q,list); _ls_q = \ + UTLIST_NEXT(_ls_q,list,next); UTLIST_RS(list); _ls_qsize--; \ } \ if (_ls_tail) { \ - _SV(_ls_tail,list); _NEXTASGN(_ls_tail,list,_ls_e,next); _RS(list); \ + UTLIST_SV(_ls_tail,list); UTLIST_NEXTASGN(_ls_tail,list,_ls_e,next); UTLIST_RS(list); \ } else { \ - _CASTASGN(list,_ls_e); \ + UTLIST_CASTASGN(list,_ls_e); \ } \ - _SV(_ls_e,list); _PREVASGN(_ls_e,list,_ls_tail,prev); _RS(list); \ + UTLIST_SV(_ls_e,list); UTLIST_PREVASGN(_ls_e,list,_ls_tail,prev); UTLIST_RS(list); \ _ls_tail = _ls_e; \ } \ _ls_p = _ls_q; \ } \ - _CASTASGN(list->prev, _ls_tail); \ - _SV(_ls_tail,list); _NEXTASGN(_ls_tail,list,NULL,next); _RS(list); \ + UTLIST_CASTASGN((list)->prev, _ls_tail); \ + UTLIST_SV(_ls_tail,list); UTLIST_NEXTASGN(_ls_tail,list,NULL,next); UTLIST_RS(list); \ if (_ls_nmerges <= 1) { \ _ls_looping=0; \ } \ @@ -243,9 +250,9 @@ do { _ls_insize = 1; \ _ls_looping = 1; \ while (_ls_looping) { \ - _CASTASGN(_ls_p,list); \ - _CASTASGN(_ls_oldhead,list); \ - list = NULL; \ + UTLIST_CASTASGN(_ls_p,list); \ + UTLIST_CASTASGN(_ls_oldhead,list); \ + (list) = NULL; \ _ls_tail = NULL; \ _ls_nmerges = 0; \ while (_ls_p) { \ @@ -254,47 +261,47 @@ do { _ls_psize = 0; \ for (_ls_i = 0; _ls_i < _ls_insize; _ls_i++) { \ _ls_psize++; \ - _SV(_ls_q,list); \ - if (_NEXT(_ls_q,list,next) == _ls_oldhead) { \ + UTLIST_SV(_ls_q,list); \ + if (UTLIST_NEXT(_ls_q,list,next) == _ls_oldhead) { \ _ls_q = NULL; \ } else { \ - _ls_q = _NEXT(_ls_q,list,next); \ + _ls_q = UTLIST_NEXT(_ls_q,list,next); \ } \ - _RS(list); \ + UTLIST_RS(list); \ if (!_ls_q) break; \ } \ _ls_qsize = _ls_insize; \ while (_ls_psize > 0 || (_ls_qsize > 0 && _ls_q)) { \ if (_ls_psize == 0) { \ - _ls_e = _ls_q; _SV(_ls_q,list); _ls_q = \ - _NEXT(_ls_q,list,next); _RS(list); _ls_qsize--; \ + _ls_e = _ls_q; UTLIST_SV(_ls_q,list); _ls_q = \ + UTLIST_NEXT(_ls_q,list,next); UTLIST_RS(list); _ls_qsize--; \ if (_ls_q == _ls_oldhead) { _ls_q = NULL; } \ } else if (_ls_qsize == 0 || !_ls_q) { \ - _ls_e = _ls_p; _SV(_ls_p,list); _ls_p = \ - _NEXT(_ls_p,list,next); _RS(list); _ls_psize--; \ + _ls_e = _ls_p; UTLIST_SV(_ls_p,list); _ls_p = \ + UTLIST_NEXT(_ls_p,list,next); UTLIST_RS(list); _ls_psize--; \ if (_ls_p == _ls_oldhead) { _ls_p = NULL; } \ } else if (cmp(_ls_p,_ls_q) <= 0) { \ - _ls_e = _ls_p; _SV(_ls_p,list); _ls_p = \ - _NEXT(_ls_p,list,next); _RS(list); _ls_psize--; \ + _ls_e = _ls_p; UTLIST_SV(_ls_p,list); _ls_p = \ + UTLIST_NEXT(_ls_p,list,next); UTLIST_RS(list); _ls_psize--; \ if (_ls_p == _ls_oldhead) { _ls_p = NULL; } \ } else { \ - _ls_e = _ls_q; _SV(_ls_q,list); _ls_q = \ - _NEXT(_ls_q,list,next); _RS(list); _ls_qsize--; \ + _ls_e = _ls_q; UTLIST_SV(_ls_q,list); _ls_q = \ + UTLIST_NEXT(_ls_q,list,next); UTLIST_RS(list); _ls_qsize--; \ if (_ls_q == _ls_oldhead) { _ls_q = NULL; } \ } \ if (_ls_tail) { \ - _SV(_ls_tail,list); _NEXTASGN(_ls_tail,list,_ls_e,next); _RS(list); \ + UTLIST_SV(_ls_tail,list); UTLIST_NEXTASGN(_ls_tail,list,_ls_e,next); UTLIST_RS(list); \ } else { \ - _CASTASGN(list,_ls_e); \ + UTLIST_CASTASGN(list,_ls_e); \ } \ - _SV(_ls_e,list); _PREVASGN(_ls_e,list,_ls_tail,prev); _RS(list); \ + UTLIST_SV(_ls_e,list); UTLIST_PREVASGN(_ls_e,list,_ls_tail,prev); UTLIST_RS(list); \ _ls_tail = _ls_e; \ } \ _ls_p = _ls_q; \ } \ - _CASTASGN(list->prev,_ls_tail); \ - _CASTASGN(_tmp,list); \ - _SV(_ls_tail,list); _NEXTASGN(_ls_tail,list,_tmp,next); _RS(list); \ + UTLIST_CASTASGN((list)->prev,_ls_tail); \ + UTLIST_CASTASGN(_tmp,list); \ + UTLIST_SV(_ls_tail,list); UTLIST_NEXTASGN(_ls_tail,list,_tmp,next); UTLIST_RS(list); \ if (_ls_nmerges <= 1) { \ _ls_looping=0; \ } \ @@ -311,8 +318,8 @@ do { #define LL_PREPEND2(head,add,next) \ do { \ - (add)->next = head; \ - head = add; \ + (add)->next = (head); \ + (head) = (add); \ } while (0) #define LL_CONCAT(head1,head2) \ @@ -322,7 +329,7 @@ do { do { \ LDECLTYPE(head1) _tmp; \ if (head1) { \ - _tmp = head1; \ + _tmp = (head1); \ while (_tmp->next) { _tmp = _tmp->next; } \ _tmp->next=(head2); \ } else { \ @@ -338,7 +345,7 @@ do { LDECLTYPE(head) _tmp; \ (add)->next=NULL; \ if (head) { \ - _tmp = head; \ + _tmp = (head); \ while (_tmp->next) { _tmp = _tmp->next; } \ _tmp->next=(add); \ } else { \ @@ -346,96 +353,76 @@ do { } \ } while (0) -#define LL_DELETE(head,del) \ - LL_DELETE2(head,del,next) +#define LL_INSERT_INORDER(head,add,cmp) \ + LL_INSERT_INORDER2(head,add,cmp,next) -#define LL_DELETE2(head,del,next) \ +#define LL_INSERT_INORDER2(head,add,cmp,next) \ do { \ LDECLTYPE(head) _tmp; \ - if ((head) == (del)) { \ - (head)=(head)->next; \ + if (head) { \ + LL_LOWER_BOUND2(head, _tmp, add, cmp, next); \ + LL_APPEND_ELEM2(head, _tmp, add, next); \ } else { \ - _tmp = head; \ - while (_tmp->next && (_tmp->next != (del))) { \ - _tmp = _tmp->next; \ - } \ - if (_tmp->next) { \ - _tmp->next = ((del)->next); \ - } \ + (head) = (add); \ + (head)->next = NULL; \ } \ } while (0) -/* Here are VS2008 replacements for LL_APPEND and LL_DELETE */ -#define LL_APPEND_VS2008(head,add) \ - LL_APPEND2_VS2008(head,add,next) +#define LL_LOWER_BOUND(head,elt,like,cmp) \ + LL_LOWER_BOUND2(head,elt,like,cmp,next) -#define LL_APPEND2_VS2008(head,add,next) \ -do { \ - if (head) { \ - (add)->next = head; /* use add->next as a temp variable */ \ - while ((add)->next->next) { (add)->next = (add)->next->next; } \ - (add)->next->next=(add); \ - } else { \ - (head)=(add); \ - } \ - (add)->next=NULL; \ -} while (0) +#define LL_LOWER_BOUND2(head,elt,like,cmp,next) \ + do { \ + if ((head) == NULL || (cmp(head, like)) >= 0) { \ + (elt) = NULL; \ + } else { \ + for ((elt) = (head); (elt)->next != NULL; (elt) = (elt)->next) { \ + if (cmp((elt)->next, like) >= 0) { \ + break; \ + } \ + } \ + } \ + } while (0) -#define LL_DELETE_VS2008(head,del) \ - LL_DELETE2_VS2008(head,del,next) +#define LL_DELETE(head,del) \ + LL_DELETE2(head,del,next) -#define LL_DELETE2_VS2008(head,del,next) \ +#define LL_DELETE2(head,del,next) \ do { \ + LDECLTYPE(head) _tmp; \ if ((head) == (del)) { \ (head)=(head)->next; \ } else { \ - char *_tmp = (char*)(head); \ - while ((head)->next && ((head)->next != (del))) { \ - head = (head)->next; \ - } \ - if ((head)->next) { \ - (head)->next = ((del)->next); \ + _tmp = (head); \ + while (_tmp->next && (_tmp->next != (del))) { \ + _tmp = _tmp->next; \ } \ - { \ - char **_head_alias = (char**)&(head); \ - *_head_alias = _tmp; \ + if (_tmp->next) { \ + _tmp->next = (del)->next; \ } \ } \ } while (0) -#ifdef NO_DECLTYPE -#undef LL_APPEND -#define LL_APPEND LL_APPEND_VS2008 -#undef LL_DELETE -#define LL_DELETE LL_DELETE_VS2008 -#undef LL_DELETE2 -#define LL_DELETE2 LL_DELETE2_VS2008 -#undef LL_APPEND2 -#define LL_APPEND2 LL_APPEND2_VS2008 -#undef LL_CONCAT /* no LL_CONCAT_VS2008 */ -#undef DL_CONCAT /* no DL_CONCAT_VS2008 */ -#endif -/* end VS2008 replacements */ #define LL_COUNT(head,el,counter) \ LL_COUNT2(head,el,counter,next) \ #define LL_COUNT2(head,el,counter,next) \ -{ \ - counter = 0; \ - LL_FOREACH2(head,el,next){ ++counter; } \ -} +do { \ + (counter) = 0; \ + LL_FOREACH2(head,el,next) { ++(counter); } \ +} while (0) #define LL_FOREACH(head,el) \ LL_FOREACH2(head,el,next) #define LL_FOREACH2(head,el,next) \ - for(el=head;el;el=(el)->next) + for ((el) = (head); el; (el) = (el)->next) #define LL_FOREACH_SAFE(head,el,tmp) \ LL_FOREACH_SAFE2(head,el,tmp,next) #define LL_FOREACH_SAFE2(head,el,tmp,next) \ - for((el)=(head);(el) && (tmp = (el)->next, 1); (el) = tmp) + for ((el) = (head); (el) && ((tmp) = (el)->next, 1); (el) = (tmp)) #define LL_SEARCH_SCALAR(head,out,field,val) \ LL_SEARCH_SCALAR2(head,out,field,val,next) @@ -445,7 +432,7 @@ do { LL_FOREACH2(head,out,next) { \ if ((out)->field == (val)) break; \ } \ -} while(0) +} while (0) #define LL_SEARCH(head,out,elt,cmp) \ LL_SEARCH2(head,out,elt,cmp,next) @@ -455,19 +442,19 @@ do { LL_FOREACH2(head,out,next) { \ if ((cmp(out,elt))==0) break; \ } \ -} while(0) +} while (0) -#define LL_REPLACE_ELEM(head, el, add) \ +#define LL_REPLACE_ELEM2(head, el, add, next) \ do { \ LDECLTYPE(head) _tmp; \ - assert(head != NULL); \ - assert(el != NULL); \ - assert(add != NULL); \ + assert((head) != NULL); \ + assert((el) != NULL); \ + assert((add) != NULL); \ (add)->next = (el)->next; \ if ((head) == (el)) { \ (head) = (add); \ } else { \ - _tmp = head; \ + _tmp = (head); \ while (_tmp->next && (_tmp->next != (el))) { \ _tmp = _tmp->next; \ } \ @@ -477,26 +464,158 @@ do { } \ } while (0) +#define LL_REPLACE_ELEM(head, el, add) \ + LL_REPLACE_ELEM2(head, el, add, next) + +#define LL_PREPEND_ELEM2(head, el, add, next) \ +do { \ + if (el) { \ + LDECLTYPE(head) _tmp; \ + assert((head) != NULL); \ + assert((add) != NULL); \ + (add)->next = (el); \ + if ((head) == (el)) { \ + (head) = (add); \ + } else { \ + _tmp = (head); \ + while (_tmp->next && (_tmp->next != (el))) { \ + _tmp = _tmp->next; \ + } \ + if (_tmp->next) { \ + _tmp->next = (add); \ + } \ + } \ + } else { \ + LL_APPEND2(head, add, next); \ + } \ +} while (0) \ + #define LL_PREPEND_ELEM(head, el, add) \ + LL_PREPEND_ELEM2(head, el, add, next) + +#define LL_APPEND_ELEM2(head, el, add, next) \ do { \ - LDECLTYPE(head) _tmp; \ - assert(head != NULL); \ - assert(el != NULL); \ - assert(add != NULL); \ - (add)->next = (el); \ - if ((head) == (el)) { \ - (head) = (add); \ + if (el) { \ + assert((head) != NULL); \ + assert((add) != NULL); \ + (add)->next = (el)->next; \ + (el)->next = (add); \ } else { \ - _tmp = head; \ - while (_tmp->next && (_tmp->next != (el))) { \ - _tmp = _tmp->next; \ + LL_PREPEND2(head, add, next); \ + } \ +} while (0) \ + +#define LL_APPEND_ELEM(head, el, add) \ + LL_APPEND_ELEM2(head, el, add, next) + +#ifdef NO_DECLTYPE +/* Here are VS2008 / NO_DECLTYPE replacements for a few functions */ + +#undef LL_CONCAT2 +#define LL_CONCAT2(head1,head2,next) \ +do { \ + char *_tmp; \ + if (head1) { \ + _tmp = (char*)(head1); \ + while ((head1)->next) { (head1) = (head1)->next; } \ + (head1)->next = (head2); \ + UTLIST_RS(head1); \ + } else { \ + (head1)=(head2); \ } \ - if (_tmp->next) { \ - _tmp->next = (add); \ +} while (0) + +#undef LL_APPEND2 +#define LL_APPEND2(head,add,next) \ +do { \ + if (head) { \ + (add)->next = head; /* use add->next as a temp variable */ \ + while ((add)->next->next) { (add)->next = (add)->next->next; } \ + (add)->next->next=(add); \ + } else { \ + (head)=(add); \ + } \ + (add)->next=NULL; \ +} while (0) + +#undef LL_INSERT_INORDER2 +#define LL_INSERT_INORDER2(head,add,cmp,next) \ +do { \ + if ((head) == NULL || (cmp(head, add)) >= 0) { \ + (add)->next = (head); \ + (head) = (add); \ + } else { \ + char *_tmp = (char*)(head); \ + while ((head)->next != NULL && (cmp((head)->next, add)) < 0) { \ + (head) = (head)->next; \ + } \ + (add)->next = (head)->next; \ + (head)->next = (add); \ + UTLIST_RS(head); \ + } \ +} while (0) + +#undef LL_DELETE2 +#define LL_DELETE2(head,del,next) \ +do { \ + if ((head) == (del)) { \ + (head)=(head)->next; \ + } else { \ + char *_tmp = (char*)(head); \ + while ((head)->next && ((head)->next != (del))) { \ + (head) = (head)->next; \ + } \ + if ((head)->next) { \ + (head)->next = ((del)->next); \ + } \ + UTLIST_RS(head); \ + } \ +} while (0) + +#undef LL_REPLACE_ELEM2 +#define LL_REPLACE_ELEM2(head, el, add, next) \ +do { \ + assert((head) != NULL); \ + assert((el) != NULL); \ + assert((add) != NULL); \ + if ((head) == (el)) { \ + (head) = (add); \ + } else { \ + (add)->next = head; \ + while ((add)->next->next && ((add)->next->next != (el))) { \ + (add)->next = (add)->next->next; \ + } \ + if ((add)->next->next) { \ + (add)->next->next = (add); \ + } \ + } \ + (add)->next = (el)->next; \ +} while (0) + +#undef LL_PREPEND_ELEM2 +#define LL_PREPEND_ELEM2(head, el, add, next) \ +do { \ + if (el) { \ + assert((head) != NULL); \ + assert((add) != NULL); \ + if ((head) == (el)) { \ + (head) = (add); \ + } else { \ + (add)->next = (head); \ + while ((add)->next->next && ((add)->next->next != (el))) { \ + (add)->next = (add)->next->next; \ + } \ + if ((add)->next->next) { \ + (add)->next->next = (add); \ + } \ + } \ + (add)->next = (el); \ + } else { \ + LL_APPEND2(head, add, next); \ } \ - } \ } while (0) \ +#endif /* NO_DECLTYPE */ /****************************************************************************** * doubly linked list macros (non-circular) * @@ -506,7 +625,7 @@ do { #define DL_PREPEND2(head,add,prev,next) \ do { \ - (add)->next = head; \ + (add)->next = (head); \ if (head) { \ (add)->prev = (head)->prev; \ (head)->prev = (add); \ @@ -531,7 +650,39 @@ do { (head)->prev = (head); \ (head)->next = NULL; \ } \ -} while (0) +} while (0) + +#define DL_INSERT_INORDER(head,add,cmp) \ + DL_INSERT_INORDER2(head,add,cmp,prev,next) + +#define DL_INSERT_INORDER2(head,add,cmp,prev,next) \ +do { \ + LDECLTYPE(head) _tmp; \ + if (head) { \ + DL_LOWER_BOUND2(head, _tmp, add, cmp, next); \ + DL_APPEND_ELEM2(head, _tmp, add, prev, next); \ + } else { \ + (head) = (add); \ + (head)->prev = (head); \ + (head)->next = NULL; \ + } \ +} while (0) + +#define DL_LOWER_BOUND(head,elt,like,cmp) \ + DL_LOWER_BOUND2(head,elt,like,cmp,next) + +#define DL_LOWER_BOUND2(head,elt,like,cmp,next) \ +do { \ + if ((head) == NULL || (cmp(head, like)) >= 0) { \ + (elt) = NULL; \ + } else { \ + for ((elt) = (head); (elt)->next != NULL; (elt) = (elt)->next) { \ + if ((cmp((elt)->next, like)) >= 0) { \ + break; \ + } \ + } \ + } \ +} while (0) #define DL_CONCAT(head1,head2) \ DL_CONCAT2(head1,head2,prev,next) @@ -541,25 +692,27 @@ do { LDECLTYPE(head1) _tmp; \ if (head2) { \ if (head1) { \ - _tmp = (head2)->prev; \ + UTLIST_CASTASGN(_tmp, (head2)->prev); \ (head2)->prev = (head1)->prev; \ (head1)->prev->next = (head2); \ - (head1)->prev = _tmp; \ + UTLIST_CASTASGN((head1)->prev, _tmp); \ } else { \ (head1)=(head2); \ } \ } \ -} while (0) +} while (0) #define DL_DELETE(head,del) \ DL_DELETE2(head,del,prev,next) #define DL_DELETE2(head,del,prev,next) \ do { \ + assert((head) != NULL); \ assert((del)->prev != NULL); \ if ((del)->prev == (del)) { \ (head)=NULL; \ - } else if ((del)==(head)) { \ + } else if ((del) == (head)) { \ + assert((del)->next != NULL); \ (del)->next->prev = (del)->prev; \ (head) = (del)->next; \ } else { \ @@ -570,29 +723,29 @@ do { (head)->prev = (del)->prev; \ } \ } \ -} while (0) +} while (0) #define DL_COUNT(head,el,counter) \ DL_COUNT2(head,el,counter,next) \ #define DL_COUNT2(head,el,counter,next) \ -{ \ - counter = 0; \ - DL_FOREACH2(head,el,next){ ++counter; } \ -} +do { \ + (counter) = 0; \ + DL_FOREACH2(head,el,next) { ++(counter); } \ +} while (0) #define DL_FOREACH(head,el) \ DL_FOREACH2(head,el,next) #define DL_FOREACH2(head,el,next) \ - for(el=head;el;el=(el)->next) + for ((el) = (head); el; (el) = (el)->next) /* this version is safe for deleting the elements during iteration */ #define DL_FOREACH_SAFE(head,el,tmp) \ DL_FOREACH_SAFE2(head,el,tmp,next) #define DL_FOREACH_SAFE2(head,el,tmp,next) \ - for((el)=(head);(el) && (tmp = (el)->next, 1); (el) = tmp) + for ((el) = (head); (el) && ((tmp) = (el)->next, 1); (el) = (tmp)) /* these are identical to their singly-linked list counterparts */ #define DL_SEARCH_SCALAR LL_SEARCH_SCALAR @@ -600,11 +753,11 @@ do { #define DL_SEARCH_SCALAR2 LL_SEARCH_SCALAR2 #define DL_SEARCH2 LL_SEARCH2 -#define DL_REPLACE_ELEM(head, el, add) \ +#define DL_REPLACE_ELEM2(head, el, add, prev, next) \ do { \ - assert(head != NULL); \ - assert(el != NULL); \ - assert(add != NULL); \ + assert((head) != NULL); \ + assert((el) != NULL); \ + assert((add) != NULL); \ if ((head) == (el)) { \ (head) = (add); \ (add)->next = (el)->next; \ @@ -626,25 +779,104 @@ do { } \ } while (0) +#define DL_REPLACE_ELEM(head, el, add) \ + DL_REPLACE_ELEM2(head, el, add, prev, next) + +#define DL_PREPEND_ELEM2(head, el, add, prev, next) \ +do { \ + if (el) { \ + assert((head) != NULL); \ + assert((add) != NULL); \ + (add)->next = (el); \ + (add)->prev = (el)->prev; \ + (el)->prev = (add); \ + if ((head) == (el)) { \ + (head) = (add); \ + } else { \ + (add)->prev->next = (add); \ + } \ + } else { \ + DL_APPEND2(head, add, prev, next); \ + } \ +} while (0) \ + #define DL_PREPEND_ELEM(head, el, add) \ + DL_PREPEND_ELEM2(head, el, add, prev, next) + +#define DL_APPEND_ELEM2(head, el, add, prev, next) \ do { \ - assert(head != NULL); \ - assert(el != NULL); \ - assert(add != NULL); \ - (add)->next = (el); \ - (add)->prev = (el)->prev; \ - (el)->prev = (add); \ - if ((head) == (el)) { \ - (head) = (add); \ + if (el) { \ + assert((head) != NULL); \ + assert((add) != NULL); \ + (add)->next = (el)->next; \ + (add)->prev = (el); \ + (el)->next = (add); \ + if ((add)->next) { \ + (add)->next->prev = (add); \ + } else { \ + (head)->prev = (add); \ + } \ } else { \ - (add)->prev->next = (add); \ + DL_PREPEND2(head, add, prev, next); \ } \ } while (0) \ +#define DL_APPEND_ELEM(head, el, add) \ + DL_APPEND_ELEM2(head, el, add, prev, next) + +#ifdef NO_DECLTYPE +/* Here are VS2008 / NO_DECLTYPE replacements for a few functions */ + +#undef DL_INSERT_INORDER2 +#define DL_INSERT_INORDER2(head,add,cmp,prev,next) \ +do { \ + if ((head) == NULL) { \ + (add)->prev = (add); \ + (add)->next = NULL; \ + (head) = (add); \ + } else if ((cmp(head, add)) >= 0) { \ + (add)->prev = (head)->prev; \ + (add)->next = (head); \ + (head)->prev = (add); \ + (head) = (add); \ + } else { \ + char *_tmp = (char*)(head); \ + while ((head)->next && (cmp((head)->next, add)) < 0) { \ + (head) = (head)->next; \ + } \ + (add)->prev = (head); \ + (add)->next = (head)->next; \ + (head)->next = (add); \ + UTLIST_RS(head); \ + if ((add)->next) { \ + (add)->next->prev = (add); \ + } else { \ + (head)->prev = (add); \ + } \ + } \ +} while (0) +#endif /* NO_DECLTYPE */ /****************************************************************************** * circular doubly linked list macros * *****************************************************************************/ +#define CDL_APPEND(head,add) \ + CDL_APPEND2(head,add,prev,next) + +#define CDL_APPEND2(head,add,prev,next) \ +do { \ + if (head) { \ + (add)->prev = (head)->prev; \ + (add)->next = (head); \ + (head)->prev = (add); \ + (add)->prev->next = (add); \ + } else { \ + (add)->prev = (add); \ + (add)->next = (add); \ + (head) = (add); \ + } \ +} while (0) + #define CDL_PREPEND(head,add) \ CDL_PREPEND2(head,add,prev,next) @@ -659,7 +891,39 @@ do { (add)->prev = (add); \ (add)->next = (add); \ } \ -(head)=(add); \ + (head) = (add); \ +} while (0) + +#define CDL_INSERT_INORDER(head,add,cmp) \ + CDL_INSERT_INORDER2(head,add,cmp,prev,next) + +#define CDL_INSERT_INORDER2(head,add,cmp,prev,next) \ +do { \ + LDECLTYPE(head) _tmp; \ + if (head) { \ + CDL_LOWER_BOUND2(head, _tmp, add, cmp, next); \ + CDL_APPEND_ELEM2(head, _tmp, add, prev, next); \ + } else { \ + (head) = (add); \ + (head)->next = (head); \ + (head)->prev = (head); \ + } \ +} while (0) + +#define CDL_LOWER_BOUND(head,elt,like,cmp) \ + CDL_LOWER_BOUND2(head,elt,like,cmp,next) + +#define CDL_LOWER_BOUND2(head,elt,like,cmp,next) \ +do { \ + if ((head) == NULL || (cmp(head, like)) >= 0) { \ + (elt) = NULL; \ + } else { \ + for ((elt) = (head); (elt)->next != (head); (elt) = (elt)->next) { \ + if ((cmp((elt)->next, like)) >= 0) { \ + break; \ + } \ + } \ + } \ } while (0) #define CDL_DELETE(head,del) \ @@ -667,37 +931,37 @@ do { #define CDL_DELETE2(head,del,prev,next) \ do { \ - if ( ((head)==(del)) && ((head)->next == (head))) { \ - (head) = 0L; \ + if (((head)==(del)) && ((head)->next == (head))) { \ + (head) = NULL; \ } else { \ (del)->next->prev = (del)->prev; \ (del)->prev->next = (del)->next; \ if ((del) == (head)) (head)=(del)->next; \ } \ -} while (0) +} while (0) #define CDL_COUNT(head,el,counter) \ CDL_COUNT2(head,el,counter,next) \ #define CDL_COUNT2(head, el, counter,next) \ -{ \ - counter = 0; \ - CDL_FOREACH2(head,el,next){ ++counter; } \ -} +do { \ + (counter) = 0; \ + CDL_FOREACH2(head,el,next) { ++(counter); } \ +} while (0) #define CDL_FOREACH(head,el) \ CDL_FOREACH2(head,el,next) #define CDL_FOREACH2(head,el,next) \ - for(el=head;el;el=((el)->next==head ? 0L : (el)->next)) + for ((el)=(head);el;(el)=(((el)->next==(head)) ? NULL : (el)->next)) #define CDL_FOREACH_SAFE(head,el,tmp1,tmp2) \ CDL_FOREACH_SAFE2(head,el,tmp1,tmp2,prev,next) #define CDL_FOREACH_SAFE2(head,el,tmp1,tmp2,prev,next) \ - for((el)=(head), ((tmp1)=(head)?((head)->prev):NULL); \ - (el) && ((tmp2)=(el)->next, 1); \ - ((el) = (((el)==(tmp1)) ? 0L : (tmp2)))) + for ((el) = (head), (tmp1) = (head) ? (head)->prev : NULL; \ + (el) && ((tmp2) = (el)->next, 1); \ + (el) = ((el) == (tmp1) ? NULL : (tmp2))) #define CDL_SEARCH_SCALAR(head,out,field,val) \ CDL_SEARCH_SCALAR2(head,out,field,val,next) @@ -707,7 +971,7 @@ do { CDL_FOREACH2(head,out,next) { \ if ((out)->field == (val)) break; \ } \ -} while(0) +} while (0) #define CDL_SEARCH(head,out,elt,cmp) \ CDL_SEARCH2(head,out,elt,cmp,next) @@ -717,13 +981,13 @@ do { CDL_FOREACH2(head,out,next) { \ if ((cmp(out,elt))==0) break; \ } \ -} while(0) +} while (0) -#define CDL_REPLACE_ELEM(head, el, add) \ +#define CDL_REPLACE_ELEM2(head, el, add, prev, next) \ do { \ - assert(head != NULL); \ - assert(el != NULL); \ - assert(add != NULL); \ + assert((head) != NULL); \ + assert((el) != NULL); \ + assert((add) != NULL); \ if ((el)->next == (el)) { \ (add)->next = (add); \ (add)->prev = (add); \ @@ -739,19 +1003,74 @@ do { } \ } while (0) +#define CDL_REPLACE_ELEM(head, el, add) \ + CDL_REPLACE_ELEM2(head, el, add, prev, next) + +#define CDL_PREPEND_ELEM2(head, el, add, prev, next) \ +do { \ + if (el) { \ + assert((head) != NULL); \ + assert((add) != NULL); \ + (add)->next = (el); \ + (add)->prev = (el)->prev; \ + (el)->prev = (add); \ + (add)->prev->next = (add); \ + if ((head) == (el)) { \ + (head) = (add); \ + } \ + } else { \ + CDL_APPEND2(head, add, prev, next); \ + } \ +} while (0) + #define CDL_PREPEND_ELEM(head, el, add) \ + CDL_PREPEND_ELEM2(head, el, add, prev, next) + +#define CDL_APPEND_ELEM2(head, el, add, prev, next) \ do { \ - assert(head != NULL); \ - assert(el != NULL); \ - assert(add != NULL); \ - (add)->next = (el); \ - (add)->prev = (el)->prev; \ - (el)->prev = (add); \ - (add)->prev->next = (add); \ - if ((head) == (el)) { \ - (head) = (add); \ + if (el) { \ + assert((head) != NULL); \ + assert((add) != NULL); \ + (add)->next = (el)->next; \ + (add)->prev = (el); \ + (el)->next = (add); \ + (add)->next->prev = (add); \ + } else { \ + CDL_PREPEND2(head, add, prev, next); \ } \ -} while (0) \ +} while (0) -#endif /* UTLIST_H */ +#define CDL_APPEND_ELEM(head, el, add) \ + CDL_APPEND_ELEM2(head, el, add, prev, next) + +#ifdef NO_DECLTYPE +/* Here are VS2008 / NO_DECLTYPE replacements for a few functions */ +#undef CDL_INSERT_INORDER2 +#define CDL_INSERT_INORDER2(head,add,cmp,prev,next) \ +do { \ + if ((head) == NULL) { \ + (add)->prev = (add); \ + (add)->next = (add); \ + (head) = (add); \ + } else if ((cmp(head, add)) >= 0) { \ + (add)->prev = (head)->prev; \ + (add)->next = (head); \ + (add)->prev->next = (add); \ + (head)->prev = (add); \ + (head) = (add); \ + } else { \ + char *_tmp = (char*)(head); \ + while ((char*)(head)->next != _tmp && (cmp((head)->next, add)) < 0) { \ + (head) = (head)->next; \ + } \ + (add)->prev = (head); \ + (add)->next = (head)->next; \ + (add)->next->prev = (add); \ + (head)->next = (add); \ + UTLIST_RS(head); \ + } \ +} while (0) +#endif /* NO_DECLTYPE */ + +#endif /* UTLIST_H */ diff --git a/contrib/libucl/utils/CMakeLists.txt b/contrib/libucl/utils/CMakeLists.txt deleted file mode 100644 index 4de95fd7b4b0..000000000000 --- a/contrib/libucl/utils/CMakeLists.txt +++ /dev/null @@ -1,12 +0,0 @@ - -PROJECT(libucl-utils C) - -FUNCTION(MAKE_UTIL UTIL_NAME UTIL_SRCS) - ADD_EXECUTABLE(${UTIL_NAME} ${UTIL_SRCS}) - TARGET_LINK_LIBRARIES(${UTIL_NAME} ucl) - INSTALL(TARGETS ${UTIL_NAME} DESTINATION bin) -ENDFUNCTION() - -MAKE_UTIL(ucl_chargen chargen.c) -MAKE_UTIL(ucl_objdump objdump.c) -MAKE_UTIL(ucl_tool ucl-tool.c) diff --git a/contrib/libucl/utils/Makefile.am b/contrib/libucl/utils/Makefile.am deleted file mode 100644 index ec85aaa5e372..000000000000 --- a/contrib/libucl/utils/Makefile.am +++ /dev/null @@ -1,23 +0,0 @@ -common_utils_cflags = -I$(top_srcdir)/include \ - -I$(top_srcdir)/src \ - -I$(top_srcdir)/uthash -common_utils_ldadd = $(top_builddir)/src/libucl.la - -ucl_chargen_SOURCES = chargen.c -ucl_chargen_LDADD = $(common_utils_ldadd) -ucl_chargen_CFLAGS = $(common_utils_cflags) - -ucl_objdump_SOURCES = objdump.c -ucl_objdump_LDADD = $(common_utils_ldadd) -ucl_objdump_CFLAGS = $(common_utils_cflags) - -ucl_tool_SOURCES = ucl-tool.c -ucl_tool_LDADD = $(common_utils_ldadd) -ucl_tool_CFLAGS = $(common_utils_cflags) - -if UTILS -UTL = ucl_chargen ucl_objdump ucl_tool -else -UTL = -endif -bin_PROGRAMS = $(UTL) diff --git a/contrib/libucl/utils/chargen.c b/contrib/libucl/utils/chargen.c deleted file mode 100644 index 398134054c21..000000000000 --- a/contrib/libucl/utils/chargen.c +++ /dev/null @@ -1,128 +0,0 @@ -/* Copyright (c) 2013, Vsevolod Stakhov - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED ''AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL AUTHOR BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/** - * @file this utility generates character table for ucl - */ - -#include <stdio.h> -#include <ctype.h> -#include <stdbool.h> - -static inline int -print_flag (const char *flag, bool *need_or, char *val) -{ - int res; - res = sprintf (val, "%s%s", *need_or ? "|" : "", flag); - - *need_or |= true; - - return res; -} - -int -main (int argc, char **argv) -{ - int i, col, r; - const char *name = "ucl_chartable"; - bool need_or; - char valbuf[2048]; - - col = 0; - - if (argc > 1) { - name = argv[1]; - } - - printf ("static const unsigned int %s[256] = {\n", name); - - for (i = 0; i < 256; i ++) { - need_or = false; - r = 0; - /* UCL_CHARACTER_VALUE_END */ - - if (i == ' ' || i == '\t') { - r += print_flag ("UCL_CHARACTER_WHITESPACE", &need_or, valbuf + r); - } - if (isspace (i)) { - r += print_flag ("UCL_CHARACTER_WHITESPACE_UNSAFE", &need_or, valbuf + r); - } - if (isalnum (i) || i >= 0x80 || i == '/' || i == '_') { - r += print_flag ("UCL_CHARACTER_KEY_START", &need_or, valbuf + r); - } - if (isalnum (i) || i == '-' || i == '_' || i == '/' || i == '.' || i >= 0x80) { - r += print_flag ("UCL_CHARACTER_KEY", &need_or, valbuf + r); - } - if (i == 0 || i == '\r' || i == '\n' || i == ']' || i == '}' || i == ';' || i == ',' || i == '#') { - r += print_flag ("UCL_CHARACTER_VALUE_END", &need_or, valbuf + r); - } - else { - if (isprint (i) || i >= 0x80) { - r += print_flag ("UCL_CHARACTER_VALUE_STR", &need_or, valbuf + r); - } - if (isdigit (i) || i == '-') { - r += print_flag ("UCL_CHARACTER_VALUE_DIGIT_START", &need_or, valbuf + r); - } - if (isalnum (i) || i == '.' || i == '-' || i == '+') { - r += print_flag ("UCL_CHARACTER_VALUE_DIGIT", &need_or, valbuf + r); - } - } - if (i == '"' || i == '\\' || i == '/' || i == 'b' || - i == 'f' || i == 'n' || i == 'r' || i == 't' || i == 'u') { - r += print_flag ("UCL_CHARACTER_ESCAPE", &need_or, valbuf + r); - } - if (i == ' ' || i == '\t' || i == ':' || i == '=') { - r += print_flag ("UCL_CHARACTER_KEY_SEP", &need_or, valbuf + r); - } - if (i == '\n' || i == '\r' || i == '\\' || i == '\b' || i == '\t' || - i == '"' || i == '\f') { - r += print_flag ("UCL_CHARACTER_JSON_UNSAFE", &need_or, valbuf + r); - } - if (i == '\n' || i == '\r' || i == '\\' || i == '\b' || i == '\t' || - i == '"' || i == '\f' || i == '=' || i == ':' || i == '{' || i == '[' || i == ' ') { - r += print_flag ("UCL_CHARACTER_UCL_UNSAFE", &need_or, valbuf + r); - } - - if (!need_or) { - r += print_flag ("UCL_CHARACTER_DENIED", &need_or, valbuf + r); - } - - if (isprint (i)) { - r += sprintf (valbuf + r, " /* %c */", i); - } - if (i != 255) { - r += sprintf (valbuf + r, ", "); - } - col += r; - if (col > 80) { - printf ("\n%s", valbuf); - col = r; - } - else { - printf ("%s", valbuf); - } - } - printf ("\n}\n"); - - return 0; -} diff --git a/contrib/libucl/utils/objdump.c b/contrib/libucl/utils/objdump.c deleted file mode 100644 index 416eca7c87e0..000000000000 --- a/contrib/libucl/utils/objdump.c +++ /dev/null @@ -1,185 +0,0 @@ -/* Copyright (c) 2013, Dmitriy V. Reshetnikov - * Copyright (c) 2013, Vsevolod Stakhov - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED ''AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL AUTHOR BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#if defined(_MSC_VER) - #include <BaseTsd.h> - - typedef SSIZE_T ssize_t; -#endif - -#include "ucl.h" - -void -ucl_obj_dump (const ucl_object_t *obj, unsigned int shift) -{ - int num = shift * 4 + 5; - char *pre = (char *) malloc (num * sizeof(char)); - const ucl_object_t *cur, *tmp; - ucl_object_iter_t it = NULL, it_obj = NULL; - - pre[--num] = 0x00; - while (num--) - pre[num] = 0x20; - - tmp = obj; - - while ((obj = ucl_object_iterate (tmp, &it, false))) { - printf ("%sucl object address: %p\n", pre + 4, obj); - if (obj->key != NULL) { - printf ("%skey: \"%s\"\n", pre, ucl_object_key (obj)); - } - printf ("%sref: %u\n", pre, obj->ref); - printf ("%slen: %u\n", pre, obj->len); - printf ("%sprev: %p\n", pre, obj->prev); - printf ("%snext: %p\n", pre, obj->next); - if (obj->type == UCL_OBJECT) { - printf ("%stype: UCL_OBJECT\n", pre); - printf ("%svalue: %p\n", pre, obj->value.ov); - it_obj = NULL; - while ((cur = ucl_object_iterate (obj, &it_obj, true))) { - ucl_obj_dump (cur, shift + 2); - } - } - else if (obj->type == UCL_ARRAY) { - printf ("%stype: UCL_ARRAY\n", pre); - printf ("%svalue: %p\n", pre, obj->value.av); - it_obj = NULL; - while ((cur = ucl_object_iterate (obj, &it_obj, true))) { - ucl_obj_dump (cur, shift + 2); - } - } - else if (obj->type == UCL_INT) { - printf ("%stype: UCL_INT\n", pre); - printf ("%svalue: %jd\n", pre, (intmax_t)ucl_object_toint (obj)); - } - else if (obj->type == UCL_FLOAT) { - printf ("%stype: UCL_FLOAT\n", pre); - printf ("%svalue: %f\n", pre, ucl_object_todouble (obj)); - } - else if (obj->type == UCL_STRING) { - printf ("%stype: UCL_STRING\n", pre); - printf ("%svalue: \"%s\"\n", pre, ucl_object_tostring (obj)); - } - else if (obj->type == UCL_BOOLEAN) { - printf ("%stype: UCL_BOOLEAN\n", pre); - printf ("%svalue: %s\n", pre, ucl_object_tostring_forced (obj)); - } - else if (obj->type == UCL_TIME) { - printf ("%stype: UCL_TIME\n", pre); - printf ("%svalue: %f\n", pre, ucl_object_todouble (obj)); - } - else if (obj->type == UCL_USERDATA) { - printf ("%stype: UCL_USERDATA\n", pre); - printf ("%svalue: %p\n", pre, obj->value.ud); - } - } - - free (pre); -} - -int -main(int argc, char **argv) -{ - const char *fn = NULL; - unsigned char *inbuf; - struct ucl_parser *parser; - int k, ret = 0; - ssize_t bufsize, r = 0; - ucl_object_t *obj = NULL; - const ucl_object_t *par; - FILE *in; - - if (argc > 1) { - fn = argv[1]; - } - - if (fn != NULL) { - in = fopen (fn, "r"); - if (in == NULL) { - exit (EXIT_FAILURE); - } - } - else { - in = stdin; - } - - parser = ucl_parser_new (0); - inbuf = malloc (BUFSIZ); - bufsize = BUFSIZ; - r = 0; - - while (!feof (in) && !ferror (in)) { - if (r == bufsize) { - inbuf = realloc (inbuf, bufsize * 2); - bufsize *= 2; - if (inbuf == NULL) { - perror ("realloc"); - exit (EXIT_FAILURE); - } - } - r += fread (inbuf + r, 1, bufsize - r, in); - } - - if (ferror (in)) { - fprintf (stderr, "Failed to read the input file.\n"); - exit (EXIT_FAILURE); - } - - ucl_parser_add_chunk (parser, inbuf, r); - fclose (in); - if (ucl_parser_get_error(parser)) { - printf ("Error occurred: %s\n", ucl_parser_get_error(parser)); - ret = 1; - goto end; - } - - obj = ucl_parser_get_object (parser); - if (ucl_parser_get_error (parser)) { - printf ("Error occurred: %s\n", ucl_parser_get_error(parser)); - ret = 1; - goto end; - } - - if (argc > 2) { - for (k = 2; k < argc; k++) { - printf ("search for \"%s\"... ", argv[k]); - par = ucl_object_lookup (obj, argv[k]); - printf ("%sfound\n", (par == NULL )?"not ":""); - ucl_obj_dump (par, 0); - } - } - else { - ucl_obj_dump (obj, 0); - } - -end: - if (parser != NULL) { - ucl_parser_free (parser); - } - if (obj != NULL) { - ucl_object_unref (obj); - } - - return ret; -} diff --git a/contrib/libucl/utils/ucl-tool.c b/contrib/libucl/utils/ucl-tool.c deleted file mode 100644 index 9b807d35c092..000000000000 --- a/contrib/libucl/utils/ucl-tool.c +++ /dev/null @@ -1,170 +0,0 @@ -/* Copyright (c) 2015, Cesanta Software - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED ''AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL AUTHOR BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "ucl.h" - -void usage(const char *name, FILE *out) { - fprintf(out, "Usage: %s [--help] [-i|--in file] [-o|--out file]\n", name); - fprintf(out, " [-s|--schema file] [-f|--format format]\n\n"); - fprintf(out, " --help - print this message and exit\n"); - fprintf(out, " --in - specify input filename " - "(default: standard input)\n"); - fprintf(out, " --out - specify output filename " - "(default: standard output)\n"); - fprintf(out, " --schema - specify schema file for validation\n"); - fprintf(out, " --format - output format. Options: ucl (default), " - "json, compact_json, yaml, msgpack\n"); -} - -int main(int argc, char **argv) { - int i; - char ch; - FILE *in = stdin, *out = stdout; - const char *schema = NULL, *parm, *val; - unsigned char *buf = NULL; - size_t size = 0, r = 0; - struct ucl_parser *parser = NULL; - ucl_object_t *obj = NULL; - ucl_emitter_t emitter = UCL_EMIT_CONFIG; - - for (i = 1; i < argc; ++i) { - parm = argv[i]; - val = ((i + 1) < argc) ? argv[++i] : NULL; - - if ((strcmp(parm, "--help") == 0) || (strcmp(parm, "-h") == 0)) { - usage(argv[0], stdout); - exit(0); - - } else if ((strcmp(parm, "--in") == 0) || (strcmp(parm, "-i") == 0)) { - if (!val) - goto err_val; - - in = fopen(val, "r"); - if (in == NULL) { - perror("fopen on input file"); - exit(EXIT_FAILURE); - } - } else if ((strcmp(parm, "--out") == 0) || (strcmp(parm, "-o") == 0)) { - if (!val) - goto err_val; - - out = fopen(val, "w"); - if (out == NULL) { - perror("fopen on output file"); - exit(EXIT_FAILURE); - } - } else if ((strcmp(parm, "--schema") == 0) || (strcmp(parm, "-s") == 0)) { - if (!val) - goto err_val; - schema = val; - - } else if ((strcmp(parm, "--format") == 0) || (strcmp(parm, "-f") == 0)) { - if (!val) - goto err_val; - - if (strcmp(val, "ucl") == 0) { - emitter = UCL_EMIT_CONFIG; - } else if (strcmp(val, "json") == 0) { - emitter = UCL_EMIT_JSON; - } else if (strcmp(val, "yaml") == 0) { - emitter = UCL_EMIT_YAML; - } else if (strcmp(val, "compact_json") == 0) { - emitter = UCL_EMIT_JSON_COMPACT; - } else if (strcmp(val, "msgpack") == 0) { - emitter = UCL_EMIT_MSGPACK; - } else { - fprintf(stderr, "Unknown output format: %s\n", val); - exit(EXIT_FAILURE); - } - } else { - usage(argv[0], stderr); - exit(EXIT_FAILURE); - } - } - - parser = ucl_parser_new(0); - buf = malloc(BUFSIZ); - size = BUFSIZ; - while (!feof(in) && !ferror(in)) { - if (r == size) { - buf = realloc(buf, size*2); - size *= 2; - if (buf == NULL) { - perror("realloc"); - exit(EXIT_FAILURE); - } - } - r += fread(buf + r, 1, size - r, in); - } - if (ferror(in)) { - fprintf(stderr, "Failed to read the input file.\n"); - exit(EXIT_FAILURE); - } - fclose(in); - if (!ucl_parser_add_chunk(parser, buf, r)) { - fprintf(stderr, "Failed to parse input file: %s\n", - ucl_parser_get_error(parser)); - exit(EXIT_FAILURE); - } - if ((obj = ucl_parser_get_object(parser)) == NULL) { - fprintf(stderr, "Failed to get root object: %s\n", - ucl_parser_get_error(parser)); - exit(EXIT_FAILURE); - } - if (schema != NULL) { - struct ucl_parser *schema_parser = ucl_parser_new(0); - ucl_object_t *schema_obj = NULL; - struct ucl_schema_error error; - - if (!ucl_parser_add_file(schema_parser, schema)) { - fprintf(stderr, "Failed to parse schema file: %s\n", - ucl_parser_get_error(schema_parser)); - exit(EXIT_FAILURE); - } - if ((schema_obj = ucl_parser_get_object(schema_parser)) == NULL) { - fprintf(stderr, "Failed to get root object: %s\n", - ucl_parser_get_error(schema_parser)); - exit(EXIT_FAILURE); - } - if (!ucl_object_validate(schema_obj, obj, &error)) { - fprintf(stderr, "Validation failed: %s\n", error.msg); - exit(EXIT_FAILURE); - } - } - - if (emitter != UCL_EMIT_MSGPACK) { - fprintf(out, "%s\n", ucl_object_emit(obj, emitter)); - } else { - size_t len; - unsigned char *res; - - res = ucl_object_emit_len(obj, emitter, &len); - fwrite(res, 1, len, out); - } - - return 0; - -err_val: - fprintf(stderr, "Parameter %s is missing mandatory value\n", parm); - usage(argv[0], stderr); - exit(EXIT_FAILURE); -} diff --git a/contrib/llvm-project/llvm/lib/ObjCopy/ELF/ELFObjcopy.cpp b/contrib/llvm-project/llvm/lib/ObjCopy/ELF/ELFObjcopy.cpp index 075455c03415..7de9b4dd2ea1 100644 --- a/contrib/llvm-project/llvm/lib/ObjCopy/ELF/ELFObjcopy.cpp +++ b/contrib/llvm-project/llvm/lib/ObjCopy/ELF/ELFObjcopy.cpp @@ -368,7 +368,7 @@ static Error updateAndRemoveSymbols(const CommonConfig &Config, // (like GroupSection or RelocationSection). This way, we know which // symbols are still 'needed' and which are not. if (Config.StripUnneeded || !Config.UnneededSymbolsToRemove.empty() || - !Config.OnlySection.empty()) { + !Config.OnlySection.empty() || Config.DiscardMode != DiscardType::None) { for (SectionBase &Sec : Obj.sections()) Sec.markSymbols(); } @@ -390,22 +390,23 @@ static Error updateAndRemoveSymbols(const CommonConfig &Config, if (Config.StripDebug && Sym.Type == STT_FILE) return true; - if ((Config.DiscardMode == DiscardType::All || - (Config.DiscardMode == DiscardType::Locals && - StringRef(Sym.Name).starts_with(".L"))) && - Sym.Binding == STB_LOCAL && Sym.getShndx() != SHN_UNDEF && - Sym.Type != STT_FILE && Sym.Type != STT_SECTION) - return true; - if ((Config.StripUnneeded || Config.UnneededSymbolsToRemove.matches(Sym.Name)) && (!Obj.isRelocatable() || isUnneededSymbol(Sym))) return true; - // We want to remove undefined symbols if all references have been stripped. - if (!Config.OnlySection.empty() && !Sym.Referenced && - Sym.getShndx() == SHN_UNDEF) - return true; + if (!Sym.Referenced) { + if ((Config.DiscardMode == DiscardType::All || + (Config.DiscardMode == DiscardType::Locals && + StringRef(Sym.Name).starts_with(".L"))) && + Sym.Binding == STB_LOCAL && Sym.getShndx() != SHN_UNDEF && + Sym.Type != STT_FILE && Sym.Type != STT_SECTION) + return true; + // We want to remove undefined symbols if all references have been + // stripped. + if (!Config.OnlySection.empty() && Sym.getShndx() == SHN_UNDEF) + return true; + } return false; }; diff --git a/contrib/llvm-project/llvm/lib/Target/PowerPC/PPCMergeStringPool.cpp b/contrib/llvm-project/llvm/lib/Target/PowerPC/PPCMergeStringPool.cpp index 309938accdf4..daf6a0e65d54 100644 --- a/contrib/llvm-project/llvm/lib/Target/PowerPC/PPCMergeStringPool.cpp +++ b/contrib/llvm-project/llvm/lib/Target/PowerPC/PPCMergeStringPool.cpp @@ -170,8 +170,9 @@ void PPCMergeStringPool::collectCandidateConstants(Module &M) { LLVM_DEBUG(dbgs() << "hasInitializer() " << Global.hasInitializer() << "\n"); - // We can only pool constants. - if (!Global.isConstant() || !Global.hasInitializer()) + // We can only pool non-thread-local constants. + if (!Global.isConstant() || !Global.hasInitializer() || + Global.isThreadLocal()) continue; // If a global constant has a section we do not try to pool it because diff --git a/contrib/lua/Makefile b/contrib/lua/Makefile index 8efa2eb3fdd6..6e21588476df 100644 --- a/contrib/lua/Makefile +++ b/contrib/lua/Makefile @@ -46,7 +46,7 @@ TO_MAN= lua.1 luac.1 # Lua version and release. V= 5.4 -R= $V.6 +R= $V.8 # Targets start here. all: $(PLAT) diff --git a/contrib/lua/README b/contrib/lua/README index 1ae97165babe..b251d296f687 100644 --- a/contrib/lua/README +++ b/contrib/lua/README @@ -1,5 +1,5 @@ -This is Lua 5.4.6, released on 02 May 2023. +This is Lua 5.4.8, released on 21 May 2025. For installation instructions, license details, and further information about Lua, see doc/readme.html. diff --git a/contrib/lua/doc/contents.html b/contrib/lua/doc/contents.html index 1231e6d2481d..18b677dbac8f 100644 --- a/contrib/lua/doc/contents.html +++ b/contrib/lua/doc/contents.html @@ -10,7 +10,7 @@ <BODY> <H1> -<A HREF="http://www.lua.org/"><IMG SRC="logo.gif" ALT="Lua"></A> +<A HREF="https://www.lua.org/"><IMG SRC="logo.gif" ALT="Lua"></A> Lua 5.4 Reference Manual </H1> @@ -18,7 +18,7 @@ Lua 5.4 Reference Manual The reference manual is the official definition of the Lua language. <BR> For a complete introduction to Lua programming, see the book -<A HREF="http://www.lua.org/pil/">Programming in Lua</A>. +<A HREF="https://www.lua.org/pil/">Programming in Lua</A>. <DIV CLASS="menubar"> <A HREF="manual.html">start</A> @@ -27,14 +27,14 @@ For a complete introduction to Lua programming, see the book · <A HREF="#index">index</A> · -<A HREF="http://www.lua.org/manual/">other versions</A> +<A HREF="https://www.lua.org/manual/">other versions</A> </DIV> <P> <SMALL> -Copyright © 2020–2023 Lua.org, PUC-Rio. +Copyright © 2020–2025 Lua.org, PUC-Rio. Freely available under the terms of the -<A HREF="http://www.lua.org/license.html">Lua license</A>. +<A HREF="https://www.lua.org/license.html">Lua license</A>. </SMALL> <H2><A NAME="contents">Contents</A></H2> @@ -668,10 +668,10 @@ Freely available under the terms of the <P CLASS="footer"> Last update: -Sat Apr 1 17:57:05 UTC 2023 +Wed May 21 21:11:33 UTC 2025 </P> <!-- -Last change: revised for Lua 5.4.5 +Last change: revised for Lua 5.4.8 --> </BODY> diff --git a/contrib/lua/doc/lua.1 b/contrib/lua/doc/lua.1 index 3f472fd81f62..3c9e000234e3 100644 --- a/contrib/lua/doc/lua.1 +++ b/contrib/lua/doc/lua.1 @@ -1,5 +1,5 @@ -.\" $Id: lua.man,v 1.14 2022/09/23 09:06:36 lhf Exp $ -.TH LUA 1 "$Date: 2022/09/23 09:06:36 $" +.\" $Id: lua.man,v 1.14 2024/05/08 18:48:27 lhf Exp $ +.TH LUA 1 "$Date: 2024/05/08 18:48:27 $" .SH NAME lua \- Lua interpreter .SH SYNOPSIS @@ -123,7 +123,7 @@ and the version-neutral variants are ignored. Code to be executed before command line options and scripts. .TP .B LUA_PATH, LUA_PATH_5_4 -Initial value of package.cpath, +Initial value of package.path, the path used by require to search for Lua loaders. .TP .B LUA_CPATH, LUA_CPATH_5_4 diff --git a/contrib/lua/doc/lua.css b/contrib/lua/doc/lua.css index cbd0799d1525..9013b445c654 100644 --- a/contrib/lua/doc/lua.css +++ b/contrib/lua/doc/lua.css @@ -143,6 +143,7 @@ table.book td.cover { table.book img { border: solid #000080 1px ; + border-radius: 2px ; } table.book span { diff --git a/contrib/lua/doc/manual.html b/contrib/lua/doc/manual.html index 0af688b343c7..8239bc2a964f 100644 --- a/contrib/lua/doc/manual.html +++ b/contrib/lua/doc/manual.html @@ -10,7 +10,7 @@ <BODY> <H1> -<A HREF="http://www.lua.org/"><IMG SRC="logo.gif" ALT="Lua"></A> +<A HREF="https://www.lua.org/"><IMG SRC="logo.gif" ALT="Lua"></A> Lua 5.4 Reference Manual </H1> @@ -19,9 +19,9 @@ by Roberto Ierusalimschy, Luiz Henrique de Figueiredo, Waldemar Celes <P> <SMALL> -Copyright © 2020–2023 Lua.org, PUC-Rio. +Copyright © 2020–2025 Lua.org, PUC-Rio. Freely available under the terms of the -<a href="http://www.lua.org/license.html">Lua license</a>. +<a href="https://www.lua.org/license.html">Lua license</a>. </SMALL> <DIV CLASS="menubar"> @@ -29,7 +29,7 @@ Freely available under the terms of the · <A HREF="contents.html#index">index</A> · -<A HREF="http://www.lua.org/manual/">other versions</A> +<A HREF="https://www.lua.org/manual/">other versions</A> </DIV> <!-- ====================================================================== --> @@ -391,7 +391,7 @@ Whenever there is an error, an <em>error object</em> is propagated with information about the error. Lua itself only generates errors whose error object is a string, -but programs may generate errors with +but programs can generate errors with any value as the error object. It is up to the Lua program or its host to handle such error objects. For historical reasons, @@ -401,7 +401,7 @@ even though it does not have to be a string. <p> When you use <a href="#pdf-xpcall"><code>xpcall</code></a> (or <a href="#lua_pcall"><code>lua_pcall</code></a>, in C) -you may give a <em>message handler</em> +you can give a <em>message handler</em> to be called in case of errors. This function is called with the original error object and returns a new error object. @@ -453,7 +453,7 @@ which is then called a <em>metamethod</em>. In the previous example, the key is the string "<code>__add</code>" and the metamethod is the function that performs the addition. Unless stated otherwise, -a metamethod may in fact be any callable value, +a metamethod can in fact be any callable value, which is either a function or a value with a <code>__call</code> metamethod. @@ -1725,7 +1725,7 @@ labels in Lua are considered statements too: <p> A label is visible in the entire block where it is defined, except inside nested functions. -A goto may jump to any visible label as long as it does not +A goto can jump to any visible label as long as it does not enter into the scope of a local variable. A label should not be declared where a label with the same name is visible, @@ -5571,7 +5571,7 @@ otherwise, returns <code>NULL</code>. <hr><h3><a name="lua_toclose"><code>lua_toclose</code></a></h3><p> -<span class="apii">[-0, +0, <em>m</em>]</span> +<span class="apii">[-0, +0, <em>v</em>]</span> <pre>void lua_toclose (lua_State *L, int index);</pre> <p> @@ -5592,6 +5592,11 @@ unless previously deactivated by <a href="#lua_closeslot"><code>lua_closeslot</c <p> +This function raises an error if the value at the given slot +neither has a <code>__close</code> metamethod nor is a false value. + + +<p> This function should not be called for an index that is equal to or below an active to-be-closed slot. @@ -5664,6 +5669,12 @@ after its last character (as in C), but can contain other zeros in its body. +<p> +This function can raise memory errors only +when converting a number to a string +(as then it may create a new string). + + @@ -11276,13 +11287,13 @@ The returned table can contain all the fields returned by <a href="#lua_getinfo" with the string <code>what</code> describing which fields to fill in. The default for <code>what</code> is to get all information available, except the table of valid lines. -If present, -the option '<code>f</code>' +The option '<code>f</code>' adds a field named <code>func</code> with the function itself. -If present, -the option '<code>L</code>' -adds a field named <code>activelines</code> with the table of -valid lines. +The option '<code>L</code>' adds a field named <code>activelines</code> +with the table of valid lines, +provided the function is a Lua function. +If the function has no debug information, +the table is empty. <p> @@ -11619,6 +11630,10 @@ Lua does not consult any environment variables. In particular, the values of <a href="#pdf-package.path"><code>package.path</code></a> and <a href="#pdf-package.cpath"><code>package.cpath</code></a> are set with the default paths defined in <code>luaconf.h</code>. +To signal to the libraries that this option is on, +the stand-alone interpreter sets the field +<code>"LUA_NOENV"</code> in the registry to a true value. +Other libraries may consult this field for the same purpose. <p> @@ -12033,13 +12048,12 @@ and LiteralString, see <a href="#3.1">§3.1</a>.) - <P CLASS="footer"> Last update: -Tue May 2 20:09:38 UTC 2023 +Wed May 21 21:09:59 UTC 2025 </P> <!-- -Last change: revised for Lua 5.4.6 +Last change: revised for Lua 5.4.8 --> </body></html> diff --git a/contrib/lua/doc/readme.html b/contrib/lua/doc/readme.html index 918ec8ed9378..a4eb59dd38c6 100644 --- a/contrib/lua/doc/readme.html +++ b/contrib/lua/doc/readme.html @@ -29,7 +29,7 @@ tt, kbd, code { <BODY> <H1> -<A HREF="http://www.lua.org/"><IMG SRC="logo.gif" ALT="Lua"></A> +<A HREF="https://www.lua.org/"><IMG SRC="logo.gif" ALT="Lua"></A> Welcome to Lua 5.4 </H1> @@ -49,29 +49,31 @@ Welcome to Lua 5.4 <P> Lua is a powerful, efficient, lightweight, embeddable scripting language developed by a -<A HREF="http://www.lua.org/authors.html">team</A> +<A HREF="https://www.lua.org/authors.html">team</A> at -<A HREF="http://www.puc-rio.br/">PUC-Rio</A>, +<A HREF="https://www.puc-rio.br/">PUC-Rio</A>, the Pontifical Catholic University of Rio de Janeiro in Brazil. Lua is <A HREF="#license">free software</A> used in -<A HREF="http://www.lua.org/uses.html">many products and projects</A> +<A HREF="https://www.lua.org/uses.html">many products and projects</A> around the world. <P> Lua's -<A HREF="http://www.lua.org/">official web site</A> +<A HREF="https://www.lua.org/">official website</A> provides complete information about Lua, including an -<A HREF="http://www.lua.org/about.html">executive summary</A> +<A HREF="https://www.lua.org/about.html">executive summary</A>, +tips on +<A HREF="https://www.lua.org/start.html">getting started</A>, and updated -<A HREF="http://www.lua.org/docs.html">documentation</A>, +<A HREF="https://www.lua.org/docs.html">documentation</A>, especially the -<A HREF="http://www.lua.org/manual/5.4/">reference manual</A>, +<A HREF="https://www.lua.org/manual/5.4/">reference manual</A>, which may differ slightly from the <A HREF="contents.html">local copy</A> distributed in this package. @@ -79,7 +81,7 @@ distributed in this package. <H2><A NAME="install">Installing Lua</A></H2> <P> Lua is distributed in -<A HREF="http://www.lua.org/ftp/">source</A> +<A HREF="https://www.lua.org/ftp/">source</A> form. You need to build it before using it. Building Lua should be straightforward @@ -88,7 +90,7 @@ Lua is implemented in pure ANSI C and compiles unmodified in all known platforms that have an ANSI C compiler. Lua also compiles unmodified as C++. The instructions given below for building Lua are for Unix-like platforms, -such as Linux and Mac OS X. +such as Linux and macOS. See also <A HREF="#other">instructions for other systems</A> and @@ -97,7 +99,7 @@ and <P> If you don't have the time or the inclination to compile Lua yourself, get a binary from -<A HREF="http://lua-users.org/wiki/LuaBinaries">LuaBinaries</A>. +<A HREF="https://luabinaries.sourceforge.net">LuaBinaries</A>. <H3>Building Lua</H3> <P> @@ -107,7 +109,7 @@ Here are the details. <OL> <LI> Open a terminal window and move to -the top-level directory, which is named <TT>lua-5.4.6</TT>. +the top-level directory, which is named <TT>lua-5.4.8</TT>. The <TT>Makefile</TT> there controls both the build process and the installation process. <P> <LI> @@ -211,8 +213,8 @@ then try "<KBD>make linux-readline MYLIBS=-ltermcap</KBD>". record the changes you've made. <P> - On the other hand, if you need to customize some Lua features, you'll need - to edit <TT>src/luaconf.h</TT> before building and installing Lua. + On the other hand, if you need to customize some Lua features, + edit <TT>src/luaconf.h</TT> before building and installing Lua. The edited file will be the one installed, and it will be used by any Lua clients that you build, to ensure consistency. Further customization is available to experts by editing the Lua sources. @@ -241,7 +243,7 @@ compiler: </DL> <P> - To use Lua as a library in your own programs, you'll need to know how to + To use Lua as a library in your own programs, you need to know how to create and use libraries with your compiler. Moreover, to dynamically load C libraries for Lua, you'll need to know how to create dynamic libraries and you'll need to make sure that the Lua API functions are accessible to @@ -284,11 +286,11 @@ lists the <H2><A NAME="license">License</A></H2> <P> -<A HREF="http://www.opensource.org/docs/definition.php"> -<IMG SRC="osi-certified-72x60.png" ALIGN="right" ALT="[osi certified]" STYLE="padding-left: 30px ;"> +<A HREF="https://opensource.org/osd"> +<IMG SRC="OSIApproved_100X125.png" ALIGN="right" ALT="[Open Source Initiative Approved License]" STYLE="padding-left: 1em" WIDTH=50> </A> Lua is free software distributed under the terms of the -<A HREF="http://www.opensource.org/licenses/mit-license.html">MIT license</A> +<A HREF="https://opensource.org/license/mit">MIT license</A> reproduced below; it may be used for any purpose, including commercial purposes, at absolutely no cost without having to ask us. @@ -296,11 +298,11 @@ at absolutely no cost without having to ask us. The only requirement is that if you do use Lua, then you should give us credit by including the appropriate copyright notice somewhere in your product or its documentation. -For details, see -<A HREF="http://www.lua.org/license.html">this</A>. +For details, see the +<A HREF="https://www.lua.org/license.html">license page</A>. <BLOCKQUOTE STYLE="padding-bottom: 0em"> -Copyright © 1994–2023 Lua.org, PUC-Rio. +Copyright © 1994–2025 Lua.org, PUC-Rio. <P> Permission is hereby granted, free of charge, to any person obtaining a copy @@ -327,10 +329,10 @@ THE SOFTWARE. <P CLASS="footer"> Last update: -Tue May 2 20:08:55 UTC 2023 +Wed May 21 21:12:01 UTC 2025 </P> <!-- -Last change: revised for Lua 5.4.6 +Last change: revised for Lua 5.4.8 --> </BODY> diff --git a/contrib/lua/src/lapi.c b/contrib/lua/src/lapi.c index 34e64af1428c..04e09cff7e0d 100644 --- a/contrib/lua/src/lapi.c +++ b/contrib/lua/src/lapi.c @@ -417,9 +417,9 @@ LUA_API const char *lua_tolstring (lua_State *L, int idx, size_t *len) { o = index2value(L, idx); /* previous call may reallocate the stack */ } if (len != NULL) - *len = vslen(o); + *len = tsslen(tsvalue(o)); lua_unlock(L); - return svalue(o); + return getstr(tsvalue(o)); } @@ -1343,7 +1343,7 @@ void lua_warning (lua_State *L, const char *msg, int tocont) { LUA_API void *lua_newuserdatauv (lua_State *L, size_t size, int nuvalue) { Udata *u; lua_lock(L); - api_check(L, 0 <= nuvalue && nuvalue < USHRT_MAX, "invalid value"); + api_check(L, 0 <= nuvalue && nuvalue < SHRT_MAX, "invalid value"); u = luaS_newudata(L, size, nuvalue); setuvalue(L, s2v(L->top.p), u); api_incr_top(L); diff --git a/contrib/lua/src/lauxlib.c b/contrib/lua/src/lauxlib.c index 4ca6c6548899..923105ed3176 100644 --- a/contrib/lua/src/lauxlib.c +++ b/contrib/lua/src/lauxlib.c @@ -80,6 +80,7 @@ static int pushglobalfuncname (lua_State *L, lua_Debug *ar) { int top = lua_gettop(L); lua_getinfo(L, "f", ar); /* push function */ lua_getfield(L, LUA_REGISTRYINDEX, LUA_LOADED_TABLE); + luaL_checkstack(L, 6, "not enough stack"); /* slots for 'findfield' */ if (findfield(L, top + 1, 2)) { const char *name = lua_tostring(L, -1); if (strncmp(name, LUA_GNAME ".", 3) == 0) { /* name start with '_G.'? */ @@ -249,11 +250,13 @@ LUALIB_API int luaL_fileresult (lua_State *L, int stat, const char *fname) { return 1; } else { + const char *msg; luaL_pushfail(L); + msg = (en != 0) ? strerror(en) : "(no extra info)"; if (fname) - lua_pushfstring(L, "%s: %s", fname, strerror(en)); + lua_pushfstring(L, "%s: %s", fname, msg); else - lua_pushstring(L, strerror(en)); + lua_pushstring(L, msg); lua_pushinteger(L, en); return 3; } @@ -732,9 +735,12 @@ static const char *getF (lua_State *L, void *ud, size_t *size) { static int errfile (lua_State *L, const char *what, int fnameindex) { - const char *serr = strerror(errno); + int err = errno; const char *filename = lua_tostring(L, fnameindex) + 1; - lua_pushfstring(L, "cannot %s %s: %s", what, filename, serr); + if (err != 0) + lua_pushfstring(L, "cannot %s %s: %s", what, filename, strerror(err)); + else + lua_pushfstring(L, "cannot %s %s", what, filename); lua_remove(L, fnameindex); return LUA_ERRFILE; } @@ -787,6 +793,7 @@ LUALIB_API int luaL_loadfilex (lua_State *L, const char *filename, } else { lua_pushfstring(L, "@%s", filename); + errno = 0; lf.f = fopen(filename, "r"); if (lf.f == NULL) return errfile(L, "open", fnameindex); } @@ -796,6 +803,7 @@ LUALIB_API int luaL_loadfilex (lua_State *L, const char *filename, if (c == LUA_SIGNATURE[0]) { /* binary file? */ lf.n = 0; /* remove possible newline */ if (filename) { /* "real" file? */ + errno = 0; lf.f = freopen(filename, "rb", lf.f); /* reopen in binary mode */ if (lf.f == NULL) return errfile(L, "reopen", fnameindex); skipcomment(lf.f, &c); /* re-read initial portion */ @@ -803,6 +811,7 @@ LUALIB_API int luaL_loadfilex (lua_State *L, const char *filename, } if (c != EOF) lf.buff[lf.n++] = c; /* 'c' is the first character of the stream */ + errno = 0; status = lua_load(L, getF, &lf, lua_tostring(L, -1), mode); readstatus = ferror(lf.f); if (filename) fclose(lf.f); /* close file (even in case of errors) */ @@ -933,7 +942,7 @@ LUALIB_API const char *luaL_tolstring (lua_State *L, int idx, size_t *len) { LUALIB_API void luaL_setfuncs (lua_State *L, const luaL_Reg *l, int nup) { luaL_checkstack(L, nup, "too many upvalues"); for (; l->name != NULL; l++) { /* fill the table with given functions */ - if (l->func == NULL) /* place holder? */ + if (l->func == NULL) /* placeholder? */ lua_pushboolean(L, 0); else { int i; @@ -1025,9 +1034,14 @@ static void *l_alloc (void *ud, void *ptr, size_t osize, size_t nsize) { } +/* +** Standard panic funcion just prints an error message. The test +** with 'lua_type' avoids possible memory errors in 'lua_tostring'. +*/ static int panic (lua_State *L) { - const char *msg = lua_tostring(L, -1); - if (msg == NULL) msg = "error object is not a string"; + const char *msg = (lua_type(L, -1) == LUA_TSTRING) + ? lua_tostring(L, -1) + : "error object is not a string"; lua_writestringerror("PANIC: unprotected error in call to Lua API (%s)\n", msg); return 0; /* return to Lua to abort */ diff --git a/contrib/lua/src/lcode.c b/contrib/lua/src/lcode.c index 8d6ce8c08bd2..85466a82ee1d 100644 --- a/contrib/lua/src/lcode.c +++ b/contrib/lua/src/lcode.c @@ -35,6 +35,7 @@ #define MAXREGS 255 +/* (note that expressions VJMP also have jumps.) */ #define hasjumps(e) ((e)->t != (e)->f) @@ -415,7 +416,7 @@ int luaK_codeABx (FuncState *fs, OpCode o, int a, unsigned int bc) { /* ** Format and emit an 'iAsBx' instruction. */ -int luaK_codeAsBx (FuncState *fs, OpCode o, int a, int bc) { +static int codeAsBx (FuncState *fs, OpCode o, int a, int bc) { unsigned int b = bc + OFFSET_sBx; lua_assert(getOpMode(o) == iAsBx); lua_assert(a <= MAXARG_A && b <= MAXARG_Bx); @@ -678,7 +679,7 @@ static int fitsBx (lua_Integer i) { void luaK_int (FuncState *fs, int reg, lua_Integer i) { if (fitsBx(i)) - luaK_codeAsBx(fs, OP_LOADI, reg, cast_int(i)); + codeAsBx(fs, OP_LOADI, reg, cast_int(i)); else luaK_codek(fs, reg, luaK_intK(fs, i)); } @@ -687,7 +688,7 @@ void luaK_int (FuncState *fs, int reg, lua_Integer i) { static void luaK_float (FuncState *fs, int reg, lua_Number f) { lua_Integer fi; if (luaV_flttointeger(f, &fi, F2Ieq) && fitsBx(fi)) - luaK_codeAsBx(fs, OP_LOADF, reg, cast_int(fi)); + codeAsBx(fs, OP_LOADF, reg, cast_int(fi)); else luaK_codek(fs, reg, luaK_numberK(fs, f)); } @@ -783,7 +784,8 @@ void luaK_dischargevars (FuncState *fs, expdesc *e) { break; } case VLOCAL: { /* already in a register */ - e->u.info = e->u.var.ridx; + int temp = e->u.var.ridx; + e->u.info = temp; /* (can't do a direct assignment; values overlap) */ e->k = VNONRELOC; /* becomes a non-relocatable value */ break; } @@ -991,7 +993,7 @@ void luaK_exp2anyregup (FuncState *fs, expdesc *e) { ** or it is a constant. */ void luaK_exp2val (FuncState *fs, expdesc *e) { - if (hasjumps(e)) + if (e->k == VJMP || hasjumps(e)) luaK_exp2anyreg(fs, e); else luaK_dischargevars(fs, e); @@ -1032,7 +1034,7 @@ static int luaK_exp2K (FuncState *fs, expdesc *e) { ** in the range of R/K indices). ** Returns 1 iff expression is K. */ -int luaK_exp2RK (FuncState *fs, expdesc *e) { +static int exp2RK (FuncState *fs, expdesc *e) { if (luaK_exp2K(fs, e)) return 1; else { /* not a constant in the right range: put it in a register */ @@ -1044,7 +1046,7 @@ int luaK_exp2RK (FuncState *fs, expdesc *e) { static void codeABRK (FuncState *fs, OpCode o, int a, int b, expdesc *ec) { - int k = luaK_exp2RK(fs, ec); + int k = exp2RK(fs, ec); luaK_codeABCk(fs, o, a, b, ec->u.info, k); } @@ -1222,7 +1224,7 @@ static void codenot (FuncState *fs, expdesc *e) { /* -** Check whether expression 'e' is a small literal string +** Check whether expression 'e' is a short literal string */ static int isKstr (FuncState *fs, expdesc *e) { return (e->k == VK && !hasjumps(e) && e->u.info <= MAXARG_B && @@ -1232,7 +1234,7 @@ static int isKstr (FuncState *fs, expdesc *e) { /* ** Check whether expression 'e' is a literal integer. */ -int luaK_isKint (expdesc *e) { +static int isKint (expdesc *e) { return (e->k == VKINT && !hasjumps(e)); } @@ -1242,7 +1244,7 @@ int luaK_isKint (expdesc *e) { ** proper range to fit in register C */ static int isCint (expdesc *e) { - return luaK_isKint(e) && (l_castS2U(e->u.ival) <= l_castS2U(MAXARG_C)); + return isKint(e) && (l_castS2U(e->u.ival) <= l_castS2U(MAXARG_C)); } @@ -1251,7 +1253,7 @@ static int isCint (expdesc *e) { ** proper range to fit in register sC */ static int isSCint (expdesc *e) { - return luaK_isKint(e) && fitsC(e->u.ival); + return isKint(e) && fitsC(e->u.ival); } @@ -1290,15 +1292,17 @@ void luaK_indexed (FuncState *fs, expdesc *t, expdesc *k) { if (t->k == VUPVAL && !isKstr(fs, k)) /* upvalue indexed by non 'Kstr'? */ luaK_exp2anyreg(fs, t); /* put it in a register */ if (t->k == VUPVAL) { - t->u.ind.t = t->u.info; /* upvalue index */ - t->u.ind.idx = k->u.info; /* literal string */ + int temp = t->u.info; /* upvalue index */ + lua_assert(isKstr(fs, k)); + t->u.ind.t = temp; /* (can't do a direct assignment; values overlap) */ + t->u.ind.idx = k->u.info; /* literal short string */ t->k = VINDEXUP; } else { /* register index of the table */ t->u.ind.t = (t->k == VLOCAL) ? t->u.var.ridx: t->u.info; if (isKstr(fs, k)) { - t->u.ind.idx = k->u.info; /* literal string */ + t->u.ind.idx = k->u.info; /* literal short string */ t->k = VINDEXSTR; } else if (isCint(k)) { @@ -1466,7 +1470,7 @@ static void codebinK (FuncState *fs, BinOpr opr, */ static int finishbinexpneg (FuncState *fs, expdesc *e1, expdesc *e2, OpCode op, int line, TMS event) { - if (!luaK_isKint(e2)) + if (!isKint(e2)) return 0; /* not an integer constant */ else { lua_Integer i2 = e2->u.ival; @@ -1599,7 +1603,7 @@ static void codeeq (FuncState *fs, BinOpr opr, expdesc *e1, expdesc *e2) { op = OP_EQI; r2 = im; /* immediate operand */ } - else if (luaK_exp2RK(fs, e2)) { /* 2nd expression is constant? */ + else if (exp2RK(fs, e2)) { /* 2nd expression is constant? */ op = OP_EQK; r2 = e2->u.info; /* constant index */ } @@ -1665,7 +1669,7 @@ void luaK_infix (FuncState *fs, BinOpr op, expdesc *v) { } case OPR_EQ: case OPR_NE: { if (!tonumeral(v, NULL)) - luaK_exp2RK(fs, v); + exp2RK(fs, v); /* else keep numeral, which may be an immediate operand */ break; } diff --git a/contrib/lua/src/lcode.h b/contrib/lua/src/lcode.h index 326582445263..0b971fc4359b 100644 --- a/contrib/lua/src/lcode.h +++ b/contrib/lua/src/lcode.h @@ -61,10 +61,8 @@ typedef enum UnOpr { OPR_MINUS, OPR_BNOT, OPR_NOT, OPR_LEN, OPR_NOUNOPR } UnOpr; LUAI_FUNC int luaK_code (FuncState *fs, Instruction i); LUAI_FUNC int luaK_codeABx (FuncState *fs, OpCode o, int A, unsigned int Bx); -LUAI_FUNC int luaK_codeAsBx (FuncState *fs, OpCode o, int A, int Bx); LUAI_FUNC int luaK_codeABCk (FuncState *fs, OpCode o, int A, int B, int C, int k); -LUAI_FUNC int luaK_isKint (expdesc *e); LUAI_FUNC int luaK_exp2const (FuncState *fs, const expdesc *e, TValue *v); LUAI_FUNC void luaK_fixline (FuncState *fs, int line); LUAI_FUNC void luaK_nil (FuncState *fs, int from, int n); @@ -76,7 +74,6 @@ LUAI_FUNC int luaK_exp2anyreg (FuncState *fs, expdesc *e); LUAI_FUNC void luaK_exp2anyregup (FuncState *fs, expdesc *e); LUAI_FUNC void luaK_exp2nextreg (FuncState *fs, expdesc *e); LUAI_FUNC void luaK_exp2val (FuncState *fs, expdesc *e); -LUAI_FUNC int luaK_exp2RK (FuncState *fs, expdesc *e); LUAI_FUNC void luaK_self (FuncState *fs, expdesc *e, expdesc *key); LUAI_FUNC void luaK_indexed (FuncState *fs, expdesc *t, expdesc *k); LUAI_FUNC void luaK_goiftrue (FuncState *fs, expdesc *e); diff --git a/contrib/lua/src/ldebug.c b/contrib/lua/src/ldebug.c index 28b1caabf77e..7264fce8a55c 100644 --- a/contrib/lua/src/ldebug.c +++ b/contrib/lua/src/ldebug.c @@ -31,12 +31,15 @@ -#define noLuaClosure(f) ((f) == NULL || (f)->c.tt == LUA_VCCL) +#define LuaClosure(f) ((f) != NULL && (f)->c.tt == LUA_VLCL) static const char *funcnamefromcall (lua_State *L, CallInfo *ci, const char **name); +static const char strlocal[] = "local"; +static const char strupval[] = "upvalue"; + static int currentpc (CallInfo *ci) { lua_assert(isLua(ci)); @@ -254,7 +257,7 @@ LUA_API const char *lua_setlocal (lua_State *L, const lua_Debug *ar, int n) { static void funcinfo (lua_Debug *ar, Closure *cl) { - if (noLuaClosure(cl)) { + if (!LuaClosure(cl)) { ar->source = "=[C]"; ar->srclen = LL("=[C]"); ar->linedefined = -1; @@ -288,29 +291,31 @@ static int nextline (const Proto *p, int currentline, int pc) { static void collectvalidlines (lua_State *L, Closure *f) { - if (noLuaClosure(f)) { + if (!LuaClosure(f)) { setnilvalue(s2v(L->top.p)); api_incr_top(L); } else { - int i; - TValue v; const Proto *p = f->l.p; int currentline = p->linedefined; Table *t = luaH_new(L); /* new table to store active lines */ sethvalue2s(L, L->top.p, t); /* push it on stack */ api_incr_top(L); - setbtvalue(&v); /* boolean 'true' to be the value of all indices */ - if (!p->is_vararg) /* regular function? */ - i = 0; /* consider all instructions */ - else { /* vararg function */ - lua_assert(GET_OPCODE(p->code[0]) == OP_VARARGPREP); - currentline = nextline(p, currentline, 0); - i = 1; /* skip first instruction (OP_VARARGPREP) */ - } - for (; i < p->sizelineinfo; i++) { /* for each instruction */ - currentline = nextline(p, currentline, i); /* get its line */ - luaH_setint(L, t, currentline, &v); /* table[line] = true */ + if (p->lineinfo != NULL) { /* proto with debug information? */ + int i; + TValue v; + setbtvalue(&v); /* boolean 'true' to be the value of all indices */ + if (!p->is_vararg) /* regular function? */ + i = 0; /* consider all instructions */ + else { /* vararg function */ + lua_assert(GET_OPCODE(p->code[0]) == OP_VARARGPREP); + currentline = nextline(p, currentline, 0); + i = 1; /* skip first instruction (OP_VARARGPREP) */ + } + for (; i < p->sizelineinfo; i++) { /* for each instruction */ + currentline = nextline(p, currentline, i); /* get its line */ + luaH_setint(L, t, currentline, &v); /* table[line] = true */ + } } } } @@ -339,7 +344,7 @@ static int auxgetinfo (lua_State *L, const char *what, lua_Debug *ar, } case 'u': { ar->nups = (f == NULL) ? 0 : f->c.nupvalues; - if (noLuaClosure(f)) { + if (!LuaClosure(f)) { ar->isvararg = 1; ar->nparams = 0; } @@ -417,40 +422,6 @@ LUA_API int lua_getinfo (lua_State *L, const char *what, lua_Debug *ar) { ** ======================================================= */ -static const char *getobjname (const Proto *p, int lastpc, int reg, - const char **name); - - -/* -** Find a "name" for the constant 'c'. -*/ -static void kname (const Proto *p, int c, const char **name) { - TValue *kvalue = &p->k[c]; - *name = (ttisstring(kvalue)) ? svalue(kvalue) : "?"; -} - - -/* -** Find a "name" for the register 'c'. -*/ -static void rname (const Proto *p, int pc, int c, const char **name) { - const char *what = getobjname(p, pc, c, name); /* search for 'c' */ - if (!(what && *what == 'c')) /* did not find a constant name? */ - *name = "?"; -} - - -/* -** Find a "name" for a 'C' value in an RK instruction. -*/ -static void rkname (const Proto *p, int pc, Instruction i, const char **name) { - int c = GETARG_C(i); /* key index */ - if (GETARG_k(i)) /* is 'c' a constant? */ - kname(p, c, name); - else /* 'c' is a register */ - rname(p, pc, c, name); -} - static int filterpc (int pc, int jmptarget) { if (pc < jmptarget) /* is code conditional (inside a jump)? */ @@ -509,28 +480,29 @@ static int findsetreg (const Proto *p, int lastpc, int reg) { /* -** Check whether table being indexed by instruction 'i' is the -** environment '_ENV' +** Find a "name" for the constant 'c'. */ -static const char *gxf (const Proto *p, int pc, Instruction i, int isup) { - int t = GETARG_B(i); /* table index */ - const char *name; /* name of indexed variable */ - if (isup) /* is an upvalue? */ - name = upvalname(p, t); - else - getobjname(p, pc, t, &name); - return (name && strcmp(name, LUA_ENV) == 0) ? "global" : "field"; +static const char *kname (const Proto *p, int index, const char **name) { + TValue *kvalue = &p->k[index]; + if (ttisstring(kvalue)) { + *name = getstr(tsvalue(kvalue)); + return "constant"; + } + else { + *name = "?"; + return NULL; + } } -static const char *getobjname (const Proto *p, int lastpc, int reg, - const char **name) { - int pc; - *name = luaF_getlocalname(p, reg + 1, lastpc); +static const char *basicgetobjname (const Proto *p, int *ppc, int reg, + const char **name) { + int pc = *ppc; + *name = luaF_getlocalname(p, reg + 1, pc); if (*name) /* is a local? */ - return "local"; + return strlocal; /* else try symbolic execution */ - pc = findsetreg(p, lastpc, reg); + *ppc = pc = findsetreg(p, pc, reg); if (pc != -1) { /* could find instruction? */ Instruction i = p->code[pc]; OpCode op = GET_OPCODE(i); @@ -538,18 +510,86 @@ static const char *getobjname (const Proto *p, int lastpc, int reg, case OP_MOVE: { int b = GETARG_B(i); /* move from 'b' to 'a' */ if (b < GETARG_A(i)) - return getobjname(p, pc, b, name); /* get name for 'b' */ + return basicgetobjname(p, ppc, b, name); /* get name for 'b' */ break; } + case OP_GETUPVAL: { + *name = upvalname(p, GETARG_B(i)); + return strupval; + } + case OP_LOADK: return kname(p, GETARG_Bx(i), name); + case OP_LOADKX: return kname(p, GETARG_Ax(p->code[pc + 1]), name); + default: break; + } + } + return NULL; /* could not find reasonable name */ +} + + +/* +** Find a "name" for the register 'c'. +*/ +static void rname (const Proto *p, int pc, int c, const char **name) { + const char *what = basicgetobjname(p, &pc, c, name); /* search for 'c' */ + if (!(what && *what == 'c')) /* did not find a constant name? */ + *name = "?"; +} + + +/* +** Find a "name" for a 'C' value in an RK instruction. +*/ +static void rkname (const Proto *p, int pc, Instruction i, const char **name) { + int c = GETARG_C(i); /* key index */ + if (GETARG_k(i)) /* is 'c' a constant? */ + kname(p, c, name); + else /* 'c' is a register */ + rname(p, pc, c, name); +} + + +/* +** Check whether table being indexed by instruction 'i' is the +** environment '_ENV'. If the table is an upvalue, get its name; +** otherwise, find some "name" for the table and check whether +** that name is the name of a local variable (and not, for instance, +** a string). Then check that, if there is a name, it is '_ENV'. +*/ +static const char *isEnv (const Proto *p, int pc, Instruction i, int isup) { + int t = GETARG_B(i); /* table index */ + const char *name; /* name of indexed variable */ + if (isup) /* is 't' an upvalue? */ + name = upvalname(p, t); + else { /* 't' is a register */ + const char *what = basicgetobjname(p, &pc, t, &name); + if (what != strlocal && what != strupval) + name = NULL; /* cannot be the variable _ENV */ + } + return (name && strcmp(name, LUA_ENV) == 0) ? "global" : "field"; +} + + +/* +** Extend 'basicgetobjname' to handle table accesses +*/ +static const char *getobjname (const Proto *p, int lastpc, int reg, + const char **name) { + const char *kind = basicgetobjname(p, &lastpc, reg, name); + if (kind != NULL) + return kind; + else if (lastpc != -1) { /* could find instruction? */ + Instruction i = p->code[lastpc]; + OpCode op = GET_OPCODE(i); + switch (op) { case OP_GETTABUP: { int k = GETARG_C(i); /* key index */ kname(p, k, name); - return gxf(p, pc, i, 1); + return isEnv(p, lastpc, i, 1); } case OP_GETTABLE: { int k = GETARG_C(i); /* key index */ - rname(p, pc, k, name); - return gxf(p, pc, i, 0); + rname(p, lastpc, k, name); + return isEnv(p, lastpc, i, 0); } case OP_GETI: { *name = "integer index"; @@ -558,24 +598,10 @@ static const char *getobjname (const Proto *p, int lastpc, int reg, case OP_GETFIELD: { int k = GETARG_C(i); /* key index */ kname(p, k, name); - return gxf(p, pc, i, 0); - } - case OP_GETUPVAL: { - *name = upvalname(p, GETARG_B(i)); - return "upvalue"; - } - case OP_LOADK: - case OP_LOADKX: { - int b = (op == OP_LOADK) ? GETARG_Bx(i) - : GETARG_Ax(p->code[pc + 1]); - if (ttisstring(&p->k[b])) { - *name = svalue(&p->k[b]); - return "constant"; - } - break; + return isEnv(p, lastpc, i, 0); } case OP_SELF: { - rkname(p, pc, i, name); + rkname(p, lastpc, i, name); return "method"; } default: break; /* go through to return NULL */ @@ -627,7 +653,7 @@ static const char *funcnamefromcode (lua_State *L, const Proto *p, default: return NULL; /* cannot find a reasonable name */ } - *name = getstr(G(L)->tmname[tm]) + 2; + *name = getshrstr(G(L)->tmname[tm]) + 2; return "metamethod"; } @@ -684,7 +710,7 @@ static const char *getupvalname (CallInfo *ci, const TValue *o, for (i = 0; i < c->nupvalues; i++) { if (c->upvals[i]->v.p == o) { *name = upvalname(c->p, i); - return "upvalue"; + return strupval; } } return NULL; @@ -866,6 +892,28 @@ static int changedline (const Proto *p, int oldpc, int newpc) { /* +** Traces Lua calls. If code is running the first instruction of a function, +** and function is not vararg, and it is not coming from an yield, +** calls 'luaD_hookcall'. (Vararg functions will call 'luaD_hookcall' +** after adjusting its variable arguments; otherwise, they could call +** a line/count hook before the call hook. Functions coming from +** an yield already called 'luaD_hookcall' before yielding.) +*/ +int luaG_tracecall (lua_State *L) { + CallInfo *ci = L->ci; + Proto *p = ci_func(ci)->p; + ci->u.l.trap = 1; /* ensure hooks will be checked */ + if (ci->u.l.savedpc == p->code) { /* first instruction (not resuming)? */ + if (p->is_vararg) + return 0; /* hooks will start at VARARGPREP instruction */ + else if (!(ci->callstatus & CIST_HOOKYIELD)) /* not yieded? */ + luaD_hookcall(L, ci); /* check 'call' hook */ + } + return 1; /* keep 'trap' on */ +} + + +/* ** Traces the execution of a Lua function. Called before the execution ** of each opcode, when debug is on. 'L->oldpc' stores the last ** instruction traced, to detect line changes. When entering a new @@ -888,12 +936,12 @@ int luaG_traceexec (lua_State *L, const Instruction *pc) { } pc++; /* reference is always next instruction */ ci->u.l.savedpc = pc; /* save 'pc' */ - counthook = (--L->hookcount == 0 && (mask & LUA_MASKCOUNT)); + counthook = (mask & LUA_MASKCOUNT) && (--L->hookcount == 0); if (counthook) resethookcount(L); /* reset count */ else if (!(mask & LUA_MASKLINE)) return 1; /* no line hook and count != 0; nothing to be done now */ - if (ci->callstatus & CIST_HOOKYIELD) { /* called hook last time? */ + if (ci->callstatus & CIST_HOOKYIELD) { /* hook yielded last time? */ ci->callstatus &= ~CIST_HOOKYIELD; /* erase mark */ return 1; /* do not call hook again (VM yielded, so it did not move) */ } @@ -915,7 +963,6 @@ int luaG_traceexec (lua_State *L, const Instruction *pc) { if (L->status == LUA_YIELD) { /* did hook yield? */ if (counthook) L->hookcount = 1; /* undo decrement to zero */ - ci->u.l.savedpc--; /* undo increment (resume will increment it again) */ ci->callstatus |= CIST_HOOKYIELD; /* mark that it yielded */ luaD_throw(L, LUA_YIELD); } diff --git a/contrib/lua/src/ldebug.h b/contrib/lua/src/ldebug.h index 2c3074c61b6f..2bfce3cb5e77 100644 --- a/contrib/lua/src/ldebug.h +++ b/contrib/lua/src/ldebug.h @@ -58,6 +58,7 @@ LUAI_FUNC const char *luaG_addinfo (lua_State *L, const char *msg, TString *src, int line); LUAI_FUNC l_noret luaG_errormsg (lua_State *L); LUAI_FUNC int luaG_traceexec (lua_State *L, const Instruction *pc); +LUAI_FUNC int luaG_tracecall (lua_State *L); #endif diff --git a/contrib/lua/src/ldo.c b/contrib/lua/src/ldo.c index 2a0017ca62a3..c92573d6e699 100644 --- a/contrib/lua/src/ldo.c +++ b/contrib/lua/src/ldo.c @@ -94,10 +94,6 @@ void luaD_seterrorobj (lua_State *L, int errcode, StkId oldtop) { setsvalue2s(L, oldtop, G(L)->memerrmsg); /* reuse preregistered msg. */ break; } - case LUA_ERRERR: { - setsvalue2s(L, oldtop, luaS_newliteral(L, "error in error handling")); - break; - } case LUA_OK: { /* special case only for closing upvalues */ setnilvalue(s2v(oldtop)); /* no error message */ break; @@ -120,6 +116,7 @@ l_noret luaD_throw (lua_State *L, int errcode) { else { /* thread has no error handler */ global_State *g = G(L); errcode = luaE_resetthread(L, errcode); /* close all upvalues */ + L->status = errcode; if (g->mainthread->errorJmp) { /* main thread has a handler? */ setobjs2s(L, g->mainthread->top.p++, L->top.p - 1); /* copy error obj. */ luaD_throw(g->mainthread, errcode); /* re-throw in main thread */ @@ -198,6 +195,16 @@ static void correctstack (lua_State *L) { /* some space for error handling */ #define ERRORSTACKSIZE (LUAI_MAXSTACK + 200) + +/* raise an error while running the message handler */ +l_noret luaD_errerr (lua_State *L) { + TString *msg = luaS_newliteral(L, "error in error handling"); + setsvalue2s(L, L->top.p, msg); + L->top.p++; /* assume EXTRA_STACK */ + luaD_throw(L, LUA_ERRERR); +} + + /* ** Reallocate the stack to a new size, correcting all pointers into it. ** In ISO C, any pointer use after the pointer has been deallocated is @@ -247,7 +254,7 @@ int luaD_growstack (lua_State *L, int n, int raiseerror) { a stack error; cannot grow further than that. */ lua_assert(stacksize(L) == ERRORSTACKSIZE); if (raiseerror) - luaD_throw(L, LUA_ERRERR); /* error inside message handler */ + luaD_errerr(L); /* error inside message handler */ return 0; /* if not 'raiseerror', just signal it */ } else if (n < LUAI_MAXSTACK) { /* avoids arithmetic overflows */ @@ -409,7 +416,7 @@ static void rethook (lua_State *L, CallInfo *ci, int nres) { ** stack, below original 'func', so that 'luaD_precall' can call it. Raise ** an error if there is no '__call' metafield. */ -StkId luaD_tryfuncTM (lua_State *L, StkId func) { +static StkId tryfuncTM (lua_State *L, StkId func) { const TValue *tm; StkId p; checkstackGCp(L, 1, func); /* space for metamethod */ @@ -568,7 +575,7 @@ int luaD_pretailcall (lua_State *L, CallInfo *ci, StkId func, return -1; } default: { /* not a function */ - func = luaD_tryfuncTM(L, func); /* try to get '__call' metamethod */ + func = tryfuncTM(L, func); /* try to get '__call' metamethod */ /* return luaD_pretailcall(L, ci, func, narg1 + 1, delta); */ narg1++; goto retry; /* try again */ @@ -609,7 +616,7 @@ CallInfo *luaD_precall (lua_State *L, StkId func, int nresults) { return ci; } default: { /* not a function */ - func = luaD_tryfuncTM(L, func); /* try to get '__call' metamethod */ + func = tryfuncTM(L, func); /* try to get '__call' metamethod */ /* return luaD_precall(L, func, nresults); */ goto retry; /* try again with metamethod */ } @@ -792,6 +799,10 @@ static void resume (lua_State *L, void *ud) { lua_assert(L->status == LUA_YIELD); L->status = LUA_OK; /* mark that it is running (again) */ if (isLua(ci)) { /* yielded inside a hook? */ + /* undo increment made by 'luaG_traceexec': instruction was not + executed yet */ + lua_assert(ci->callstatus & CIST_HOOKYIELD); + ci->u.l.savedpc--; L->top.p = firstArg; /* discard arguments */ luaV_execute(L, ci); /* just continue running Lua code */ } diff --git a/contrib/lua/src/ldo.h b/contrib/lua/src/ldo.h index 1aa446ad09e9..4de9540ec807 100644 --- a/contrib/lua/src/ldo.h +++ b/contrib/lua/src/ldo.h @@ -60,6 +60,7 @@ /* type of protected functions, to be ran by 'runprotected' */ typedef void (*Pfunc) (lua_State *L, void *ud); +LUAI_FUNC l_noret luaD_errerr (lua_State *L); LUAI_FUNC void luaD_seterrorobj (lua_State *L, int errcode, StkId oldtop); LUAI_FUNC int luaD_protectedparser (lua_State *L, ZIO *z, const char *name, const char *mode); @@ -71,7 +72,6 @@ LUAI_FUNC int luaD_pretailcall (lua_State *L, CallInfo *ci, StkId func, LUAI_FUNC CallInfo *luaD_precall (lua_State *L, StkId func, int nResults); LUAI_FUNC void luaD_call (lua_State *L, StkId func, int nResults); LUAI_FUNC void luaD_callnoyield (lua_State *L, StkId func, int nResults); -LUAI_FUNC StkId luaD_tryfuncTM (lua_State *L, StkId func); LUAI_FUNC int luaD_closeprotected (lua_State *L, ptrdiff_t level, int status); LUAI_FUNC int luaD_pcall (lua_State *L, Pfunc func, void *u, ptrdiff_t oldtop, ptrdiff_t ef); diff --git a/contrib/lua/src/lgc.c b/contrib/lua/src/lgc.c index a3094ff57126..5817f9eec35a 100644 --- a/contrib/lua/src/lgc.c +++ b/contrib/lua/src/lgc.c @@ -542,10 +542,12 @@ static void traversestrongtable (global_State *g, Table *h) { static lu_mem traversetable (global_State *g, Table *h) { const char *weakkey, *weakvalue; const TValue *mode = gfasttm(g, h->metatable, TM_MODE); + TString *smode; markobjectN(g, h->metatable); - if (mode && ttisstring(mode) && /* is there a weak mode? */ - (cast_void(weakkey = strchr(svalue(mode), 'k')), - cast_void(weakvalue = strchr(svalue(mode), 'v')), + if (mode && ttisshrstring(mode) && /* is there a weak mode? */ + (cast_void(smode = tsvalue(mode)), + cast_void(weakkey = strchr(getshrstr(smode), 'k')), + cast_void(weakvalue = strchr(getshrstr(smode), 'v')), (weakkey || weakvalue))) { /* is really weak? */ if (!weakkey) /* strong keys? */ traverseweakvalue(g, h); @@ -638,7 +640,9 @@ static int traversethread (global_State *g, lua_State *th) { for (uv = th->openupval; uv != NULL; uv = uv->u.open.next) markobject(g, uv); /* open upvalues cannot be collected */ if (g->gcstate == GCSatomic) { /* final traversal? */ - for (; o < th->stack_last.p + EXTRA_STACK; o++) + if (!g->gcemergency) + luaD_shrinkstack(th); /* do not change stack in emergency cycle */ + for (o = th->top.p; o < th->stack_last.p + EXTRA_STACK; o++) setnilvalue(s2v(o)); /* clear dead stack slice */ /* 'remarkupvals' may have removed thread from 'twups' list */ if (!isintwups(th) && th->openupval != NULL) { @@ -646,8 +650,6 @@ static int traversethread (global_State *g, lua_State *th) { g->twups = th; } } - else if (!g->gcemergency) - luaD_shrinkstack(th); /* do not change stack in emergency cycle */ return 1 + stacksize(th); } @@ -1409,7 +1411,7 @@ static void stepgenfull (lua_State *L, global_State *g) { setminordebt(g); } else { /* another bad collection; stay in incremental mode */ - g->GCestimate = gettotalbytes(g); /* first estimate */; + g->GCestimate = gettotalbytes(g); /* first estimate */ entersweep(L); luaC_runtilstate(L, bitmask(GCSpause)); /* finish collection */ setpause(g); @@ -1604,7 +1606,7 @@ static lu_mem singlestep (lua_State *L) { case GCSenteratomic: { work = atomic(L); /* work is what was traversed by 'atomic' */ entersweep(L); - g->GCestimate = gettotalbytes(g); /* first estimate */; + g->GCestimate = gettotalbytes(g); /* first estimate */ break; } case GCSswpallgc: { /* sweep "regular" objects */ @@ -1710,6 +1712,8 @@ static void fullinc (lua_State *L, global_State *g) { entersweep(L); /* sweep everything to turn them back to white */ /* finish any pending sweep phase to start a new cycle */ luaC_runtilstate(L, bitmask(GCSpause)); + luaC_runtilstate(L, bitmask(GCSpropagate)); /* start new cycle */ + g->gcstate = GCSenteratomic; /* go straight to atomic phase */ luaC_runtilstate(L, bitmask(GCScallfin)); /* run up to finalizers */ /* estimate must be correct after a full GC cycle */ lua_assert(g->GCestimate == gettotalbytes(g)); diff --git a/contrib/lua/src/liolib.c b/contrib/lua/src/liolib.c index b08397da45da..c5075f3e78a9 100644 --- a/contrib/lua/src/liolib.c +++ b/contrib/lua/src/liolib.c @@ -245,8 +245,8 @@ static int f_gc (lua_State *L) { */ static int io_fclose (lua_State *L) { LStream *p = tolstream(L); - int res = fclose(p->f); - return luaL_fileresult(L, (res == 0), NULL); + errno = 0; + return luaL_fileresult(L, (fclose(p->f) == 0), NULL); } @@ -272,6 +272,7 @@ static int io_open (lua_State *L) { LStream *p = newfile(L); const char *md = mode; /* to traverse/check mode */ luaL_argcheck(L, l_checkmode(md), 2, "invalid mode"); + errno = 0; p->f = fopen(filename, mode); return (p->f == NULL) ? luaL_fileresult(L, 0, filename) : 1; } @@ -292,6 +293,7 @@ static int io_popen (lua_State *L) { const char *mode = luaL_optstring(L, 2, "r"); LStream *p = newprefile(L); luaL_argcheck(L, l_checkmodep(mode), 2, "invalid mode"); + errno = 0; p->f = l_popen(L, filename, mode); p->closef = &io_pclose; return (p->f == NULL) ? luaL_fileresult(L, 0, filename) : 1; @@ -300,6 +302,7 @@ static int io_popen (lua_State *L) { static int io_tmpfile (lua_State *L) { LStream *p = newfile(L); + errno = 0; p->f = tmpfile(); return (p->f == NULL) ? luaL_fileresult(L, 0, NULL) : 1; } @@ -567,6 +570,7 @@ static int g_read (lua_State *L, FILE *f, int first) { int nargs = lua_gettop(L) - 1; int n, success; clearerr(f); + errno = 0; if (nargs == 0) { /* no arguments? */ success = read_line(L, f, 1); n = first + 1; /* to return 1 result */ @@ -660,6 +664,7 @@ static int io_readline (lua_State *L) { static int g_write (lua_State *L, FILE *f, int arg) { int nargs = lua_gettop(L) - arg; int status = 1; + errno = 0; for (; nargs--; arg++) { if (lua_type(L, arg) == LUA_TNUMBER) { /* optimization: could be done exactly as for strings */ @@ -678,7 +683,8 @@ static int g_write (lua_State *L, FILE *f, int arg) { } if (l_likely(status)) return 1; /* file handle already on stack top */ - else return luaL_fileresult(L, status, NULL); + else + return luaL_fileresult(L, status, NULL); } @@ -703,6 +709,7 @@ static int f_seek (lua_State *L) { l_seeknum offset = (l_seeknum)p3; luaL_argcheck(L, (lua_Integer)offset == p3, 3, "not an integer in proper range"); + errno = 0; op = l_fseek(f, offset, mode[op]); if (l_unlikely(op)) return luaL_fileresult(L, 0, NULL); /* error */ @@ -719,19 +726,25 @@ static int f_setvbuf (lua_State *L) { FILE *f = tofile(L); int op = luaL_checkoption(L, 2, NULL, modenames); lua_Integer sz = luaL_optinteger(L, 3, LUAL_BUFFERSIZE); - int res = setvbuf(f, NULL, mode[op], (size_t)sz); + int res; + errno = 0; + res = setvbuf(f, NULL, mode[op], (size_t)sz); return luaL_fileresult(L, res == 0, NULL); } static int io_flush (lua_State *L) { - return luaL_fileresult(L, fflush(getiofile(L, IO_OUTPUT)) == 0, NULL); + FILE *f = getiofile(L, IO_OUTPUT); + errno = 0; + return luaL_fileresult(L, fflush(f) == 0, NULL); } static int f_flush (lua_State *L) { - return luaL_fileresult(L, fflush(tofile(L)) == 0, NULL); + FILE *f = tofile(L); + errno = 0; + return luaL_fileresult(L, fflush(f) == 0, NULL); } @@ -773,7 +786,7 @@ static const luaL_Reg meth[] = { ** metamethods for file handles */ static const luaL_Reg metameth[] = { - {"__index", NULL}, /* place holder */ + {"__index", NULL}, /* placeholder */ {"__gc", f_gc}, {"__close", f_gc}, {"__tostring", f_tostring}, diff --git a/contrib/lua/src/lmathlib.c b/contrib/lua/src/lmathlib.c index d0b1e1e5d6f5..438106348084 100644 --- a/contrib/lua/src/lmathlib.c +++ b/contrib/lua/src/lmathlib.c @@ -249,6 +249,15 @@ static int math_type (lua_State *L) { ** =================================================================== */ +/* +** This code uses lots of shifts. ANSI C does not allow shifts greater +** than or equal to the width of the type being shifted, so some shifts +** are written in convoluted ways to match that restriction. For +** preprocessor tests, it assumes a width of 32 bits, so the maximum +** shift there is 31 bits. +*/ + + /* number of binary digits in the mantissa of a float */ #define FIGS l_floatatt(MANT_DIG) @@ -271,16 +280,19 @@ static int math_type (lua_State *L) { /* 'long' has at least 64 bits */ #define Rand64 unsigned long +#define SRand64 long #elif !defined(LUA_USE_C89) && defined(LLONG_MAX) /* there is a 'long long' type (which must have at least 64 bits) */ #define Rand64 unsigned long long +#define SRand64 long long #elif ((LUA_MAXUNSIGNED >> 31) >> 31) >= 3 /* 'lua_Unsigned' has at least 64 bits */ #define Rand64 lua_Unsigned +#define SRand64 lua_Integer #endif @@ -319,23 +331,30 @@ static Rand64 nextrand (Rand64 *state) { } -/* must take care to not shift stuff by more than 63 slots */ - - /* ** Convert bits from a random integer into a float in the ** interval [0,1), getting the higher FIG bits from the ** random unsigned integer and converting that to a float. +** Some old Microsoft compilers cannot cast an unsigned long +** to a floating-point number, so we use a signed long as an +** intermediary. When lua_Number is float or double, the shift ensures +** that 'sx' is non negative; in that case, a good compiler will remove +** the correction. */ /* must throw out the extra (64 - FIGS) bits */ #define shift64_FIG (64 - FIGS) -/* to scale to [0, 1), multiply by scaleFIG = 2^(-FIGS) */ +/* 2^(-FIGS) == 2^-1 / 2^(FIGS-1) */ #define scaleFIG (l_mathop(0.5) / ((Rand64)1 << (FIGS - 1))) static lua_Number I2d (Rand64 x) { - return (lua_Number)(trim64(x) >> shift64_FIG) * scaleFIG; + SRand64 sx = (SRand64)(trim64(x) >> shift64_FIG); + lua_Number res = (lua_Number)(sx) * scaleFIG; + if (sx < 0) + res += l_mathop(1.0); /* correct the two's complement if negative */ + lua_assert(0 <= res && res < 1); + return res; } /* convert a 'Rand64' to a 'lua_Unsigned' */ @@ -471,8 +490,6 @@ static lua_Number I2d (Rand64 x) { #else /* 32 < FIGS <= 64 */ -/* must take care to not shift stuff by more than 31 slots */ - /* 2^(-FIGS) = 1.0 / 2^30 / 2^3 / 2^(FIGS-33) */ #define scaleFIG \ (l_mathop(1.0) / (UONE << 30) / l_mathop(8.0) / (UONE << (FIGS - 33))) diff --git a/contrib/lua/src/loadlib.c b/contrib/lua/src/loadlib.c index d792dffaa03b..6d289fcebb8c 100644 --- a/contrib/lua/src/loadlib.c +++ b/contrib/lua/src/loadlib.c @@ -25,15 +25,6 @@ /* -** LUA_IGMARK is a mark to ignore all before it when building the -** luaopen_ function name. -*/ -#if !defined (LUA_IGMARK) -#define LUA_IGMARK "-" -#endif - - -/* ** LUA_CSUBSEP is the character that replaces dots in submodule names ** when searching for a C loader. ** LUA_LSUBSEP is the character that replaces dots in submodule names diff --git a/contrib/lua/src/lobject.c b/contrib/lua/src/lobject.c index f73ffc6d92bd..9cfa5227eb46 100644 --- a/contrib/lua/src/lobject.c +++ b/contrib/lua/src/lobject.c @@ -542,7 +542,7 @@ const char *luaO_pushvfstring (lua_State *L, const char *fmt, va_list argp) { addstr2buff(&buff, fmt, strlen(fmt)); /* rest of 'fmt' */ clearbuff(&buff); /* empty buffer into the stack */ lua_assert(buff.pushed == 1); - return svalue(s2v(L->top.p - 1)); + return getstr(tsvalue(s2v(L->top.p - 1))); } diff --git a/contrib/lua/src/lobject.h b/contrib/lua/src/lobject.h index 556608e4aa21..980e42f8c27a 100644 --- a/contrib/lua/src/lobject.h +++ b/contrib/lua/src/lobject.h @@ -386,7 +386,7 @@ typedef struct GCObject { typedef struct TString { CommonHeader; lu_byte extra; /* reserved words for short strings; "has hash" for longs */ - lu_byte shrlen; /* length for short strings */ + lu_byte shrlen; /* length for short strings, 0xFF for long strings */ unsigned int hash; union { size_t lnglen; /* length for long strings */ @@ -398,19 +398,17 @@ typedef struct TString { /* -** Get the actual string (array of bytes) from a 'TString'. +** Get the actual string (array of bytes) from a 'TString'. (Generic +** version and specialized versions for long and short strings.) */ -#define getstr(ts) ((ts)->contents) +#define getstr(ts) ((ts)->contents) +#define getlngstr(ts) check_exp((ts)->shrlen == 0xFF, (ts)->contents) +#define getshrstr(ts) check_exp((ts)->shrlen != 0xFF, (ts)->contents) -/* get the actual string (array of bytes) from a Lua value */ -#define svalue(o) getstr(tsvalue(o)) - /* get string length from 'TString *s' */ -#define tsslen(s) ((s)->tt == LUA_VSHRSTR ? (s)->shrlen : (s)->u.lnglen) - -/* get string length from 'TValue *o' */ -#define vslen(o) tsslen(tsvalue(o)) +#define tsslen(s) \ + ((s)->shrlen != 0xFF ? (s)->shrlen : (s)->u.lnglen) /* }================================================================== */ diff --git a/contrib/lua/src/lopcodes.h b/contrib/lua/src/lopcodes.h index 4c55145399ff..46911cac14e0 100644 --- a/contrib/lua/src/lopcodes.h +++ b/contrib/lua/src/lopcodes.h @@ -210,15 +210,15 @@ OP_LOADNIL,/* A B R[A], R[A+1], ..., R[A+B] := nil */ OP_GETUPVAL,/* A B R[A] := UpValue[B] */ OP_SETUPVAL,/* A B UpValue[B] := R[A] */ -OP_GETTABUP,/* A B C R[A] := UpValue[B][K[C]:string] */ +OP_GETTABUP,/* A B C R[A] := UpValue[B][K[C]:shortstring] */ OP_GETTABLE,/* A B C R[A] := R[B][R[C]] */ OP_GETI,/* A B C R[A] := R[B][C] */ -OP_GETFIELD,/* A B C R[A] := R[B][K[C]:string] */ +OP_GETFIELD,/* A B C R[A] := R[B][K[C]:shortstring] */ -OP_SETTABUP,/* A B C UpValue[A][K[B]:string] := RK(C) */ +OP_SETTABUP,/* A B C UpValue[A][K[B]:shortstring] := RK(C) */ OP_SETTABLE,/* A B C R[A][R[B]] := RK(C) */ OP_SETI,/* A B C R[A][B] := RK(C) */ -OP_SETFIELD,/* A B C R[A][K[B]:string] := RK(C) */ +OP_SETFIELD,/* A B C R[A][K[B]:shortstring] := RK(C) */ OP_NEWTABLE,/* A B C k R[A] := {} */ diff --git a/contrib/lua/src/loslib.c b/contrib/lua/src/loslib.c index ad5a92768852..ba80d72c4575 100644 --- a/contrib/lua/src/loslib.c +++ b/contrib/lua/src/loslib.c @@ -155,6 +155,7 @@ static int os_execute (lua_State *L) { static int os_remove (lua_State *L) { const char *filename = luaL_checkstring(L, 1); + errno = 0; return luaL_fileresult(L, remove(filename) == 0, filename); } @@ -162,6 +163,7 @@ static int os_remove (lua_State *L) { static int os_rename (lua_State *L) { const char *fromname = luaL_checkstring(L, 1); const char *toname = luaL_checkstring(L, 2); + errno = 0; return luaL_fileresult(L, rename(fromname, toname) == 0, NULL); } diff --git a/contrib/lua/src/lparser.c b/contrib/lua/src/lparser.c index b745f236f068..1ac82990e0c3 100644 --- a/contrib/lua/src/lparser.c +++ b/contrib/lua/src/lparser.c @@ -198,7 +198,7 @@ static int new_localvar (LexState *ls, TString *name) { checklimit(fs, dyd->actvar.n + 1 - fs->firstlocal, MAXVARS, "local variables"); luaM_growvector(L, dyd->actvar.arr, dyd->actvar.n + 1, - dyd->actvar.size, Vardesc, USHRT_MAX, "local variables"); + dyd->actvar.size, Vardesc, SHRT_MAX, "local variables"); var = &dyd->actvar.arr[dyd->actvar.n++]; var->vd.kind = VDKREG; /* default */ var->vd.name = name; @@ -849,12 +849,11 @@ static void recfield (LexState *ls, ConsControl *cc) { FuncState *fs = ls->fs; int reg = ls->fs->freereg; expdesc tab, key, val; - if (ls->t.token == TK_NAME) { - checklimit(fs, cc->nh, MAX_INT, "items in a constructor"); + if (ls->t.token == TK_NAME) codename(ls, &key); - } else /* ls->t.token == '[' */ yindex(ls, &key); + checklimit(fs, cc->nh, MAX_INT, "items in a constructor"); cc->nh++; checknext(ls, '='); tab = *cc->t; @@ -1022,10 +1021,11 @@ static int explist (LexState *ls, expdesc *v) { } -static void funcargs (LexState *ls, expdesc *f, int line) { +static void funcargs (LexState *ls, expdesc *f) { FuncState *fs = ls->fs; expdesc args; int base, nparams; + int line = ls->linenumber; switch (ls->t.token) { case '(': { /* funcargs -> '(' [ explist ] ')' */ luaX_next(ls); @@ -1063,8 +1063,8 @@ static void funcargs (LexState *ls, expdesc *f, int line) { } init_exp(f, VCALL, luaK_codeABC(fs, OP_CALL, base, nparams+1, 2)); luaK_fixline(fs, line); - fs->freereg = base+1; /* call remove function and arguments and leaves - (unless changed) one result */ + fs->freereg = base+1; /* call removes function and arguments and leaves + one result (unless changed later) */ } @@ -1103,7 +1103,6 @@ static void suffixedexp (LexState *ls, expdesc *v) { /* suffixedexp -> primaryexp { '.' NAME | '[' exp ']' | ':' NAME funcargs | funcargs } */ FuncState *fs = ls->fs; - int line = ls->linenumber; primaryexp(ls, v); for (;;) { switch (ls->t.token) { @@ -1123,12 +1122,12 @@ static void suffixedexp (LexState *ls, expdesc *v) { luaX_next(ls); codename(ls, &key); luaK_self(fs, v, &key); - funcargs(ls, v, line); + funcargs(ls, v); break; } case '(': case TK_STRING: case '{': { /* funcargs */ luaK_exp2nextreg(fs, v); - funcargs(ls, v, line); + funcargs(ls, v); break; } default: return; diff --git a/contrib/lua/src/lstate.c b/contrib/lua/src/lstate.c index 1e925e5ad4cb..f3f2ccfdd5fb 100644 --- a/contrib/lua/src/lstate.c +++ b/contrib/lua/src/lstate.c @@ -119,7 +119,7 @@ CallInfo *luaE_extendCI (lua_State *L) { /* ** free all CallInfo structures not in use by a thread */ -void luaE_freeCI (lua_State *L) { +static void freeCI (lua_State *L) { CallInfo *ci = L->ci; CallInfo *next = ci->next; ci->next = NULL; @@ -166,7 +166,7 @@ void luaE_checkcstack (lua_State *L) { if (getCcalls(L) == LUAI_MAXCCALLS) luaG_runerror(L, "C stack overflow"); else if (getCcalls(L) >= (LUAI_MAXCCALLS / 10 * 11)) - luaD_throw(L, LUA_ERRERR); /* error while handling stack error */ + luaD_errerr(L); /* error while handling stack error */ } @@ -204,7 +204,7 @@ static void freestack (lua_State *L) { if (L->stack.p == NULL) return; /* stack not completely built yet */ L->ci = &L->base_ci; /* free the entire 'ci' list */ - luaE_freeCI(L); + freeCI(L); lua_assert(L->nci == 0); luaM_freearray(L, L->stack.p, stacksize(L) + EXTRA_STACK); /* free stack */ } @@ -272,7 +272,9 @@ static void close_state (lua_State *L) { luaC_freeallobjects(L); /* just collect its objects */ else { /* closing a fully built state */ L->ci = &L->base_ci; /* unwind CallInfo list */ + L->errfunc = 0; /* stack unwind can "throw away" the error function */ luaD_closeprotected(L, 1, LUA_OK); /* close all upvalues */ + L->top.p = L->stack.p + 1; /* empty the stack to run finalizers */ luaC_freeallobjects(L); /* collect all objects */ luai_userstateclose(L); } @@ -328,6 +330,7 @@ int luaE_resetthread (lua_State *L, int status) { if (status == LUA_YIELD) status = LUA_OK; L->status = LUA_OK; /* so it can run __close metamethods */ + L->errfunc = 0; /* stack unwind can "throw away" the error function */ status = luaD_closeprotected(L, 1, status); if (status != LUA_OK) /* errors? */ luaD_seterrorobj(L, status, L->stack.p + 1); @@ -433,7 +436,7 @@ void luaE_warning (lua_State *L, const char *msg, int tocont) { void luaE_warnerror (lua_State *L, const char *where) { TValue *errobj = s2v(L->top.p - 1); /* error object */ const char *msg = (ttisstring(errobj)) - ? svalue(errobj) + ? getstr(tsvalue(errobj)) : "error object is not a string"; /* produce warning "error in %s (%s)" (where, msg) */ luaE_warning(L, "error in ", 1); diff --git a/contrib/lua/src/lstate.h b/contrib/lua/src/lstate.h index 8bf6600e3441..007704c826be 100644 --- a/contrib/lua/src/lstate.h +++ b/contrib/lua/src/lstate.h @@ -181,7 +181,7 @@ struct CallInfo { union { struct { /* only for Lua functions */ const Instruction *savedpc; - volatile l_signalT trap; + volatile l_signalT trap; /* function is tracing lines/counts */ int nextraargs; /* # of extra arguments in vararg functions */ } l; struct { /* only for C functions */ @@ -396,7 +396,6 @@ union GCUnion { LUAI_FUNC void luaE_setdebt (global_State *g, l_mem debt); LUAI_FUNC void luaE_freethread (lua_State *L, lua_State *L1); LUAI_FUNC CallInfo *luaE_extendCI (lua_State *L); -LUAI_FUNC void luaE_freeCI (lua_State *L); LUAI_FUNC void luaE_shrinkCI (lua_State *L); LUAI_FUNC void luaE_checkcstack (lua_State *L); LUAI_FUNC void luaE_incCstack (lua_State *L); diff --git a/contrib/lua/src/lstring.c b/contrib/lua/src/lstring.c index 13dcaf4259bc..97757355c0b6 100644 --- a/contrib/lua/src/lstring.c +++ b/contrib/lua/src/lstring.c @@ -36,7 +36,7 @@ int luaS_eqlngstr (TString *a, TString *b) { lua_assert(a->tt == LUA_VLNGSTR && b->tt == LUA_VLNGSTR); return (a == b) || /* same instance or... */ ((len == b->u.lnglen) && /* equal length and ... */ - (memcmp(getstr(a), getstr(b), len) == 0)); /* equal contents */ + (memcmp(getlngstr(a), getlngstr(b), len) == 0)); /* equal contents */ } @@ -52,7 +52,7 @@ unsigned int luaS_hashlongstr (TString *ts) { lua_assert(ts->tt == LUA_VLNGSTR); if (ts->extra == 0) { /* no hash? */ size_t len = ts->u.lnglen; - ts->hash = luaS_hash(getstr(ts), len, ts->hash); + ts->hash = luaS_hash(getlngstr(ts), len, ts->hash); ts->extra = 1; /* now it has its hash */ } return ts->hash; @@ -157,6 +157,7 @@ static TString *createstrobj (lua_State *L, size_t l, int tag, unsigned int h) { TString *luaS_createlngstrobj (lua_State *L, size_t l) { TString *ts = createstrobj(L, l, LUA_VLNGSTR, G(L)->seed); ts->u.lnglen = l; + ts->shrlen = 0xFF; /* signals that it is a long string */ return ts; } @@ -193,7 +194,7 @@ static TString *internshrstr (lua_State *L, const char *str, size_t l) { TString **list = &tb->hash[lmod(h, tb->size)]; lua_assert(str != NULL); /* otherwise 'memcmp'/'memcpy' are undefined */ for (ts = *list; ts != NULL; ts = ts->u.hnext) { - if (l == ts->shrlen && (memcmp(str, getstr(ts), l * sizeof(char)) == 0)) { + if (l == ts->shrlen && (memcmp(str, getshrstr(ts), l * sizeof(char)) == 0)) { /* found! */ if (isdead(g, ts)) /* dead (but not collected yet)? */ changewhite(ts); /* resurrect it */ @@ -206,8 +207,8 @@ static TString *internshrstr (lua_State *L, const char *str, size_t l) { list = &tb->hash[lmod(h, tb->size)]; /* rehash with new size */ } ts = createstrobj(L, l, LUA_VSHRSTR, h); - memcpy(getstr(ts), str, l * sizeof(char)); ts->shrlen = cast_byte(l); + memcpy(getshrstr(ts), str, l * sizeof(char)); ts->u.hnext = *list; *list = ts; tb->nuse++; @@ -223,10 +224,10 @@ TString *luaS_newlstr (lua_State *L, const char *str, size_t l) { return internshrstr(L, str, l); else { TString *ts; - if (l_unlikely(l >= (MAX_SIZE - sizeof(TString))/sizeof(char))) + if (l_unlikely(l * sizeof(char) >= (MAX_SIZE - sizeof(TString)))) luaM_toobig(L); ts = luaS_createlngstrobj(L, l); - memcpy(getstr(ts), str, l * sizeof(char)); + memcpy(getlngstr(ts), str, l * sizeof(char)); return ts; } } diff --git a/contrib/lua/src/ltable.c b/contrib/lua/src/ltable.c index 3c690c5f1751..3353c047939a 100644 --- a/contrib/lua/src/ltable.c +++ b/contrib/lua/src/ltable.c @@ -252,7 +252,7 @@ LUAI_FUNC unsigned int luaH_realasize (const Table *t) { return t->alimit; /* this is the size */ else { unsigned int size = t->alimit; - /* compute the smallest power of 2 not smaller than 'n' */ + /* compute the smallest power of 2 not smaller than 'size' */ size |= (size >> 1); size |= (size >> 2); size |= (size >> 4); @@ -662,7 +662,8 @@ static Node *getfreepos (Table *t) { ** put new key in its main position; otherwise (colliding node is in its main ** position), new key goes to an empty position. */ -void luaH_newkey (lua_State *L, Table *t, const TValue *key, TValue *value) { +static void luaH_newkey (lua_State *L, Table *t, const TValue *key, + TValue *value) { Node *mp; TValue aux; if (l_unlikely(ttisnil(key))) @@ -721,22 +722,36 @@ void luaH_newkey (lua_State *L, Table *t, const TValue *key, TValue *value) { /* ** Search function for integers. If integer is inside 'alimit', get it -** directly from the array part. Otherwise, if 'alimit' is not equal to -** the real size of the array, key still can be in the array part. In -** this case, try to avoid a call to 'luaH_realasize' when key is just -** one more than the limit (so that it can be incremented without -** changing the real size of the array). +** directly from the array part. Otherwise, if 'alimit' is not +** the real size of the array, the key still can be in the array part. +** In this case, do the "Xmilia trick" to check whether 'key-1' is +** smaller than the real size. +** The trick works as follow: let 'p' be an integer such that +** '2^(p+1) >= alimit > 2^p', or '2^(p+1) > alimit-1 >= 2^p'. +** That is, 2^(p+1) is the real size of the array, and 'p' is the highest +** bit on in 'alimit-1'. What we have to check becomes 'key-1 < 2^(p+1)'. +** We compute '(key-1) & ~(alimit-1)', which we call 'res'; it will +** have the 'p' bit cleared. If the key is outside the array, that is, +** 'key-1 >= 2^(p+1)', then 'res' will have some bit on higher than 'p', +** therefore it will be larger or equal to 'alimit', and the check +** will fail. If 'key-1 < 2^(p+1)', then 'res' has no bit on higher than +** 'p', and as the bit 'p' itself was cleared, 'res' will be smaller +** than 2^p, therefore smaller than 'alimit', and the check succeeds. +** As special cases, when 'alimit' is 0 the condition is trivially false, +** and when 'alimit' is 1 the condition simplifies to 'key-1 < alimit'. +** If key is 0 or negative, 'res' will have its higher bit on, so that +** if cannot be smaller than alimit. */ const TValue *luaH_getint (Table *t, lua_Integer key) { - if (l_castS2U(key) - 1u < t->alimit) /* 'key' in [1, t->alimit]? */ + lua_Unsigned alimit = t->alimit; + if (l_castS2U(key) - 1u < alimit) /* 'key' in [1, t->alimit]? */ return &t->array[key - 1]; - else if (!limitequalsasize(t) && /* key still may be in the array part? */ - (l_castS2U(key) == t->alimit + 1 || - l_castS2U(key) - 1u < luaH_realasize(t))) { + else if (!isrealasize(t) && /* key still may be in the array part? */ + (((l_castS2U(key) - 1u) & ~(alimit - 1u)) < alimit)) { t->alimit = cast_uint(key); /* probably '#t' is here now */ return &t->array[key - 1]; } - else { + else { /* key is not in the array part; check the hash */ Node *n = hashint(t, key); for (;;) { /* check whether 'key' is somewhere in the chain */ if (keyisinteger(n) && keyival(n) == key) diff --git a/contrib/lua/src/ltable.h b/contrib/lua/src/ltable.h index 75dd9e26e015..8e6890342348 100644 --- a/contrib/lua/src/ltable.h +++ b/contrib/lua/src/ltable.h @@ -41,8 +41,6 @@ LUAI_FUNC void luaH_setint (lua_State *L, Table *t, lua_Integer key, LUAI_FUNC const TValue *luaH_getshortstr (Table *t, TString *key); LUAI_FUNC const TValue *luaH_getstr (Table *t, TString *key); LUAI_FUNC const TValue *luaH_get (Table *t, const TValue *key); -LUAI_FUNC void luaH_newkey (lua_State *L, Table *t, const TValue *key, - TValue *value); LUAI_FUNC void luaH_set (lua_State *L, Table *t, const TValue *key, TValue *value); LUAI_FUNC void luaH_finishset (lua_State *L, Table *t, const TValue *key, diff --git a/contrib/lua/src/ltm.h b/contrib/lua/src/ltm.h index c309e2ae10e3..73b833c605da 100644 --- a/contrib/lua/src/ltm.h +++ b/contrib/lua/src/ltm.h @@ -9,7 +9,6 @@ #include "lobject.h" -#include "lstate.h" /* @@ -96,8 +95,8 @@ LUAI_FUNC int luaT_callorderiTM (lua_State *L, const TValue *p1, int v2, int inv, int isfloat, TMS event); LUAI_FUNC void luaT_adjustvarargs (lua_State *L, int nfixparams, - CallInfo *ci, const Proto *p); -LUAI_FUNC void luaT_getvarargs (lua_State *L, CallInfo *ci, + struct CallInfo *ci, const Proto *p); +LUAI_FUNC void luaT_getvarargs (lua_State *L, struct CallInfo *ci, StkId where, int wanted); diff --git a/contrib/lua/src/lua.c b/contrib/lua/src/lua.c index 0ff884545304..4a90e55dd94b 100644 --- a/contrib/lua/src/lua.c +++ b/contrib/lua/src/lua.c @@ -115,12 +115,13 @@ static void l_message (const char *pname, const char *msg) { /* ** Check whether 'status' is not OK and, if so, prints the error -** message on the top of the stack. It assumes that the error object -** is a string, as it was either generated by Lua or by 'msghandler'. +** message on the top of the stack. */ static int report (lua_State *L, int status) { if (status != LUA_OK) { const char *msg = lua_tostring(L, -1); + if (msg == NULL) + msg = "(error message not a string)"; l_message(progname, msg); lua_pop(L, 1); /* remove message */ } @@ -210,12 +211,17 @@ static int dostring (lua_State *L, const char *s, const char *name) { /* ** Receives 'globname[=modname]' and runs 'globname = require(modname)'. +** If there is no explicit modname and globname contains a '-', cut +** the suffix after '-' (the "version") to make the global name. */ static int dolibrary (lua_State *L, char *globname) { int status; + char *suffix = NULL; char *modname = strchr(globname, '='); - if (modname == NULL) /* no explicit name? */ + if (modname == NULL) { /* no explicit name? */ modname = globname; /* module name is equal to global name */ + suffix = strchr(modname, *LUA_IGMARK); /* look for a suffix mark */ + } else { *modname = '\0'; /* global name ends here */ modname++; /* module name starts after the '=' */ @@ -223,8 +229,11 @@ static int dolibrary (lua_State *L, char *globname) { lua_getglobal(L, "require"); lua_pushstring(L, modname); status = docall(L, 1, 1); /* call 'require(modname)' */ - if (status == LUA_OK) + if (status == LUA_OK) { + if (suffix != NULL) /* is there a suffix mark? */ + *suffix = '\0'; /* remove suffix from global name */ lua_setglobal(L, globname); /* globname = require(modname) */ + } return report(L, status); } @@ -481,10 +490,8 @@ static int incomplete (lua_State *L, int status) { if (status == LUA_ERRSYNTAX) { size_t lmsg; const char *msg = lua_tolstring(L, -1, &lmsg); - if (lmsg >= marklen && strcmp(msg + lmsg - marklen, EOFMARK) == 0) { - lua_pop(L, 1); + if (lmsg >= marklen && strcmp(msg + lmsg - marklen, EOFMARK) == 0) return 1; - } } return 0; /* else... */ } @@ -499,9 +506,9 @@ static int pushline (lua_State *L, int firstline) { size_t l; const char *prmt = get_prompt(L, firstline); int readstatus = lua_readline(L, b, prmt); - if (readstatus == 0) - return 0; /* no input (prompt will be popped by caller) */ lua_pop(L, 1); /* remove prompt */ + if (readstatus == 0) + return 0; /* no input */ l = strlen(b); if (l > 0 && b[l-1] == '\n') /* line ends with newline? */ b[--l] = '\0'; /* remove it */ @@ -543,8 +550,9 @@ static int multiline (lua_State *L) { int status = luaL_loadbuffer(L, line, len, "=stdin"); /* try it */ if (!incomplete(L, status) || !pushline(L, 0)) { lua_saveline(L, line); /* keep history */ - return status; /* cannot or should not try to add continuation line */ + return status; /* should not or cannot try to add continuation line */ } + lua_remove(L, -2); /* remove error message (from incomplete line) */ lua_pushliteral(L, "\n"); /* add newline... */ lua_insert(L, -2); /* ...between the two lines */ lua_concat(L, 3); /* join them */ diff --git a/contrib/lua/src/lua.h b/contrib/lua/src/lua.h index fd16cf8050b8..f3ea590d9cd6 100644 --- a/contrib/lua/src/lua.h +++ b/contrib/lua/src/lua.h @@ -18,14 +18,14 @@ #define LUA_VERSION_MAJOR "5" #define LUA_VERSION_MINOR "4" -#define LUA_VERSION_RELEASE "6" +#define LUA_VERSION_RELEASE "8" #define LUA_VERSION_NUM 504 -#define LUA_VERSION_RELEASE_NUM (LUA_VERSION_NUM * 100 + 6) +#define LUA_VERSION_RELEASE_NUM (LUA_VERSION_NUM * 100 + 8) #define LUA_VERSION "Lua " LUA_VERSION_MAJOR "." LUA_VERSION_MINOR #define LUA_RELEASE LUA_VERSION "." LUA_VERSION_RELEASE -#define LUA_COPYRIGHT LUA_RELEASE " Copyright (C) 1994-2023 Lua.org, PUC-Rio" +#define LUA_COPYRIGHT LUA_RELEASE " Copyright (C) 1994-2025 Lua.org, PUC-Rio" #define LUA_AUTHORS "R. Ierusalimschy, L. H. de Figueiredo, W. Celes" @@ -497,7 +497,7 @@ struct lua_Debug { /****************************************************************************** -* Copyright (C) 1994-2023 Lua.org, PUC-Rio. +* Copyright (C) 1994-2025 Lua.org, PUC-Rio. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the diff --git a/contrib/lua/src/luaconf.h b/contrib/lua/src/luaconf.h index e517fb4d2e75..c7ca969e321f 100644 --- a/contrib/lua/src/luaconf.h +++ b/contrib/lua/src/luaconf.h @@ -257,6 +257,15 @@ #endif + +/* +** LUA_IGMARK is a mark to ignore all after it when building the +** module name (e.g., used to build the luaopen_ function name). +** Typically, the suffix after the mark is the module version, +** as in "mod-v1.2.so". +*/ +#define LUA_IGMARK "-" + /* }================================================================== */ diff --git a/contrib/lua/src/lundump.c b/contrib/lua/src/lundump.c index 02aed64fb622..e8d92a8534ff 100644 --- a/contrib/lua/src/lundump.c +++ b/contrib/lua/src/lundump.c @@ -81,7 +81,7 @@ static size_t loadUnsigned (LoadState *S, size_t limit) { static size_t loadSize (LoadState *S) { - return loadUnsigned(S, ~(size_t)0); + return loadUnsigned(S, MAX_SIZET); } @@ -122,7 +122,7 @@ static TString *loadStringN (LoadState *S, Proto *p) { ts = luaS_createlngstrobj(L, size); /* create string */ setsvalue2s(L, L->top.p, ts); /* anchor it ('loadVector' can GC) */ luaD_inctop(L); - loadVector(S, getstr(ts), size); /* load directly in final place */ + loadVector(S, getlngstr(ts), size); /* load directly in final place */ L->top.p--; /* pop string */ } luaC_objbarrier(L, p, ts); diff --git a/contrib/lua/src/lundump.h b/contrib/lua/src/lundump.h index f3748a998075..a97676ca1852 100644 --- a/contrib/lua/src/lundump.h +++ b/contrib/lua/src/lundump.h @@ -21,8 +21,7 @@ /* ** Encode major-minor version in one byte, one nibble for each */ -#define MYINT(s) (s[0]-'0') /* assume one-digit numerals */ -#define LUAC_VERSION (MYINT(LUA_VERSION_MAJOR)*16+MYINT(LUA_VERSION_MINOR)) +#define LUAC_VERSION (((LUA_VERSION_NUM / 100) * 16) + LUA_VERSION_NUM % 100) #define LUAC_FORMAT 0 /* this is the official format */ diff --git a/contrib/lua/src/lvm.c b/contrib/lua/src/lvm.c index 9d1bdfb0bd6e..45b47e7c8793 100644 --- a/contrib/lua/src/lvm.c +++ b/contrib/lua/src/lvm.c @@ -95,8 +95,10 @@ static int l_strton (const TValue *obj, TValue *result) { lua_assert(obj != result); if (!cvt2num(obj)) /* is object not a string? */ return 0; - else - return (luaO_str2num(svalue(obj), result) == vslen(obj) + 1); + else { + TString *st = tsvalue(obj); + return (luaO_str2num(getstr(st), result) == tsslen(st) + 1); + } } @@ -341,7 +343,10 @@ void luaV_finishset (lua_State *L, const TValue *t, TValue *key, lua_assert(isempty(slot)); /* slot must be empty */ tm = fasttm(L, h->metatable, TM_NEWINDEX); /* get metamethod */ if (tm == NULL) { /* no metamethod? */ + sethvalue2s(L, L->top.p, h); /* anchor 't' */ + L->top.p++; /* assume EXTRA_STACK */ luaH_finishset(L, h, key, slot, val); /* set new value */ + L->top.p--; invalidateTMcache(h); luaC_barrierback(L, obj2gco(h), val); return; @@ -370,30 +375,32 @@ void luaV_finishset (lua_State *L, const TValue *t, TValue *key, /* -** Compare two strings 'ls' x 'rs', returning an integer less-equal- -** -greater than zero if 'ls' is less-equal-greater than 'rs'. +** Compare two strings 'ts1' x 'ts2', returning an integer less-equal- +** -greater than zero if 'ts1' is less-equal-greater than 'ts2'. ** The code is a little tricky because it allows '\0' in the strings -** and it uses 'strcoll' (to respect locales) for each segments -** of the strings. +** and it uses 'strcoll' (to respect locales) for each segment +** of the strings. Note that segments can compare equal but still +** have different lengths. */ -static int l_strcmp (const TString *ls, const TString *rs) { - const char *l = getstr(ls); - size_t ll = tsslen(ls); - const char *r = getstr(rs); - size_t lr = tsslen(rs); +static int l_strcmp (const TString *ts1, const TString *ts2) { + const char *s1 = getstr(ts1); + size_t rl1 = tsslen(ts1); /* real length */ + const char *s2 = getstr(ts2); + size_t rl2 = tsslen(ts2); for (;;) { /* for each segment */ - int temp = strcoll(l, r); + int temp = strcoll(s1, s2); if (temp != 0) /* not equal? */ return temp; /* done */ else { /* strings are equal up to a '\0' */ - size_t len = strlen(l); /* index of first '\0' in both strings */ - if (len == lr) /* 'rs' is finished? */ - return (len == ll) ? 0 : 1; /* check 'ls' */ - else if (len == ll) /* 'ls' is finished? */ - return -1; /* 'ls' is less than 'rs' ('rs' is not finished) */ - /* both strings longer than 'len'; go on comparing after the '\0' */ - len++; - l += len; ll -= len; r += len; lr -= len; + size_t zl1 = strlen(s1); /* index of first '\0' in 's1' */ + size_t zl2 = strlen(s2); /* index of first '\0' in 's2' */ + if (zl2 == rl2) /* 's2' is finished? */ + return (zl1 == rl1) ? 0 : 1; /* check 's1' */ + else if (zl1 == rl1) /* 's1' is finished? */ + return -1; /* 's1' is less than 's2' ('s2' is not finished) */ + /* both strings longer than 'zl'; go on comparing after the '\0' */ + zl1++; zl2++; + s1 += zl1; rl1 -= zl1; s2 += zl2; rl2 -= zl2; } } } @@ -628,8 +635,9 @@ int luaV_equalobj (lua_State *L, const TValue *t1, const TValue *t2) { static void copy2buff (StkId top, int n, char *buff) { size_t tl = 0; /* size already copied */ do { - size_t l = vslen(s2v(top - n)); /* length of string being copied */ - memcpy(buff + tl, svalue(s2v(top - n)), l * sizeof(char)); + TString *st = tsvalue(s2v(top - n)); + size_t l = tsslen(st); /* length of string being copied */ + memcpy(buff + tl, getstr(st), l * sizeof(char)); tl += l; } while (--n > 0); } @@ -655,12 +663,12 @@ void luaV_concat (lua_State *L, int total) { } else { /* at least two non-empty string values; get as many as possible */ - size_t tl = vslen(s2v(top - 1)); + size_t tl = tsslen(tsvalue(s2v(top - 1))); TString *ts; /* collect total length and number of strings */ for (n = 1; n < total && tostring(L, s2v(top - n - 1)); n++) { - size_t l = vslen(s2v(top - n - 1)); - if (l_unlikely(l >= (MAX_SIZE/sizeof(char)) - tl)) { + size_t l = tsslen(tsvalue(s2v(top - n - 1))); + if (l_unlikely(l >= MAX_SIZE - sizeof(TString) - tl)) { L->top.p = top - total; /* pop strings to avoid wasting stack */ luaG_runerror(L, "string length overflow"); } @@ -673,7 +681,7 @@ void luaV_concat (lua_State *L, int total) { } else { /* long string; copy strings directly to final result */ ts = luaS_createlngstrobj(L, tl); - copy2buff(top, n, getstr(ts)); + copy2buff(top, n, getlngstr(ts)); } setsvalue2s(L, top - n, ts); /* create result */ } @@ -1159,18 +1167,11 @@ void luaV_execute (lua_State *L, CallInfo *ci) { startfunc: trap = L->hookmask; returning: /* trap already set */ - cl = clLvalue(s2v(ci->func.p)); + cl = ci_func(ci); k = cl->p->k; pc = ci->u.l.savedpc; - if (l_unlikely(trap)) { - if (pc == cl->p->code) { /* first instruction (not resuming)? */ - if (cl->p->is_vararg) - trap = 0; /* hooks will start after VARARGPREP instruction */ - else /* check 'call' hook */ - luaD_hookcall(L, ci); - } - ci->u.l.trap = 1; /* assume trap is on, for now */ - } + if (l_unlikely(trap)) + trap = luaG_tracecall(L); base = ci->func.p + 1; /* main loop of interpreter */ for (;;) { @@ -1257,7 +1258,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) { const TValue *slot; TValue *upval = cl->upvals[GETARG_B(i)]->v.p; TValue *rc = KC(i); - TString *key = tsvalue(rc); /* key must be a string */ + TString *key = tsvalue(rc); /* key must be a short string */ if (luaV_fastget(L, upval, key, slot, luaH_getshortstr)) { setobj2s(L, ra, slot); } @@ -1300,7 +1301,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) { const TValue *slot; TValue *rb = vRB(i); TValue *rc = KC(i); - TString *key = tsvalue(rc); /* key must be a string */ + TString *key = tsvalue(rc); /* key must be a short string */ if (luaV_fastget(L, rb, key, slot, luaH_getshortstr)) { setobj2s(L, ra, slot); } @@ -1313,7 +1314,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) { TValue *upval = cl->upvals[GETARG_A(i)]->v.p; TValue *rb = KB(i); TValue *rc = RKC(i); - TString *key = tsvalue(rb); /* key must be a string */ + TString *key = tsvalue(rb); /* key must be a short string */ if (luaV_fastget(L, upval, key, slot, luaH_getshortstr)) { luaV_finishfastset(L, upval, slot, rc); } @@ -1356,7 +1357,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) { const TValue *slot; TValue *rb = KB(i); TValue *rc = RKC(i); - TString *key = tsvalue(rb); /* key must be a string */ + TString *key = tsvalue(rb); /* key must be a short string */ if (luaV_fastget(L, s2v(ra), key, slot, luaH_getshortstr)) { luaV_finishfastset(L, s2v(ra), slot, rc); } diff --git a/contrib/mandoc/roff_term.c b/contrib/mandoc/roff_term.c index 8f95aa920790..85d2caeb2749 100644 --- a/contrib/mandoc/roff_term.c +++ b/contrib/mandoc/roff_term.c @@ -165,6 +165,7 @@ roff_term_pre_po(ROFF_TERM_ARGS) static int polast; /* Previously requested. */ static int po; /* Currently requested. */ static int pouse; /* Currently used. */ + int pomin; /* Minimum to be used. */ int pomax; /* Maximum to be used. */ int ponew; /* Newly requested. */ @@ -186,9 +187,9 @@ roff_term_pre_po(ROFF_TERM_ARGS) po = ponew; /* Truncate to the range [-offset, 60], remember, and apply it. */ + pomin = -p->tcol->offset; pomax = term_len(p, 60); - pouse = po >= pomax ? pomax : - po < -(int)p->tcol->offset ? -p->tcol->offset : po; + pouse = po > pomax ? pomax : po < pomin ? pomin : po; p->tcol->offset += pouse; } diff --git a/contrib/tzcode/Makefile b/contrib/tzcode/Makefile index 0087b4596515..2130582c2deb 100644 --- a/contrib/tzcode/Makefile +++ b/contrib/tzcode/Makefile @@ -137,7 +137,7 @@ TIME_T_ALTERNATIVES_TAIL = int_least32_t.ck uint_least32_t.ck \ uint_least64_t.ck # What kind of TZif data files to generate. (TZif is the binary time -# zone data format that zic generates; see Internet RFC 8536.) +# zone data format that zic generates; see Internet RFC 9636.) # If you want only POSIX time, with time values interpreted as # seconds since the epoch (not counting leap seconds), use # REDO= posix_only @@ -255,6 +255,7 @@ LDLIBS= # -DHAVE_UNISTD_H=0 if <unistd.h> does not work* # -DHAVE_UTMPX_H=0 if <utmpx.h> does not work* # -Dlocale_t=XXX if your system uses XXX instead of locale_t +# -DMKTIME_MIGHT_OVERFLOW if mktime might fail due to time_t overflow # -DPORT_TO_C89 if tzcode should also run on mostly-C89 platforms+ # Typically it is better to use a later standard. For example, # with GCC 4.9.4 (2016), prefer '-std=gnu11' to '-DPORT_TO_C89'. @@ -262,7 +263,7 @@ LDLIBS= # feature (integers at least 64 bits wide) and maybe more. # -DRESERVE_STD_EXT_IDS if your platform reserves standard identifiers # with external linkage, e.g., applications cannot define 'localtime'. -# -Dssize_t=long on hosts like MS-Windows that lack ssize_t +# -Dssize_t=int on hosts like MS-Windows that lack ssize_t # -DSUPPORT_C89=0 if the tzcode library should not support C89 callers # Although -DSUPPORT_C89=0 might work around latent bugs in callers, # it does not conform to POSIX. @@ -285,7 +286,7 @@ LDLIBS= # This mishandles some past timestamps, as US DST rules have changed. # It also mishandles settings like TZ='EET-2EEST' for eastern Europe, # as Europe and US DST rules differ. -# -DTZNAME_MAXIMUM=N to limit time zone abbreviations to N bytes (default 255) +# -DTZNAME_MAXIMUM=N to limit time zone abbreviations to N bytes (default 254) # -DUNINIT_TRAP if reading uninitialized storage can cause problems # other than simply getting garbage data # -DUSE_LTZ=0 to build zdump with the system time zone library @@ -319,7 +320,8 @@ GCC_DEBUG_FLAGS = -DGCC_LINT -g3 -O3 \ $(GCC_INSTRUMENT) \ -Wall -Wextra \ -Walloc-size-larger-than=100000 -Warray-bounds=2 \ - -Wbad-function-cast -Wbidi-chars=any,ucn -Wcast-align=strict -Wdate-time \ + -Wbad-function-cast -Wbidi-chars=any,ucn -Wcast-align=strict -Wcast-qual \ + -Wdate-time \ -Wdeclaration-after-statement -Wdouble-promotion \ -Wduplicated-branches -Wduplicated-cond -Wflex-array-member-not-at-end \ -Wformat=2 -Wformat-overflow=2 -Wformat-signedness -Wformat-truncation \ @@ -336,7 +338,7 @@ GCC_DEBUG_FLAGS = -DGCC_LINT -g3 -O3 \ -Wsuggest-attribute=noreturn -Wsuggest-attribute=pure \ -Wtrampolines -Wundef -Wunused-macros -Wuse-after-free=3 \ -Wvariadic-macros -Wvla -Wwrite-strings \ - -Wno-format-nonliteral -Wno-sign-compare + -Wno-format-nonliteral -Wno-sign-compare -Wno-type-limits # # If your system has a "GMT offset" field in its "struct tm"s # (or if you decide to add such a field in your system's "time.h" file), @@ -614,8 +616,8 @@ TZS_YEAR= 2050 TZS_CUTOFF_FLAG= -c $(TZS_YEAR) TZS= to$(TZS_YEAR).tzs TZS_NEW= to$(TZS_YEAR)new.tzs -TZS_DEPS= $(YDATA) asctime.c localtime.c \ - private.h tzfile.h zdump.c zic.c +TZS_DEPS= $(YDATA) localtime.c private.h \ + strftime.c tzfile.h zdump.c zic.c TZDATA_DIST = $(COMMON) $(DATA) $(MISC) # EIGHT_YARDS is just a yard short of the whole ENCHILADA. EIGHT_YARDS = $(TZDATA_DIST) $(DOCS) $(SOURCES) tzdata.zi @@ -855,10 +857,10 @@ tzselect: tzselect.ksh version chmod +x $@.out mv $@.out $@ -check: check_mild back.ck +check: check_mild back.ck now.ck check_mild: check_web check_zishrink \ character-set.ck white-space.ck links.ck mainguard.ck \ - name-lengths.ck now.ck slashed-abbrs.ck sorted.ck \ + name-lengths.ck slashed-abbrs.ck sorted.ck \ tables.ck ziguard.ck tzs.ck # True if UTF8_LOCALE does not work; @@ -1103,7 +1105,7 @@ set-timestamps.out: $(EIGHT_YARDS) touch -md @1 test.out; then \ rm -f test.out && \ for file in $$files; do \ - if git diff --quiet $$file; then \ + if git diff --quiet HEAD $$file; then \ time=$$(TZ=UTC0 git log -1 \ --format='tformat:%cd' \ --date='format:%Y-%m-%dT%H:%M:%SZ' \ @@ -1354,13 +1356,13 @@ long-long.ck unsigned.ck: $(VERSION_DEPS) zonenames: tzdata.zi @$(AWK) '/^Z/ { print $$2 } /^L/ { print $$3 }' tzdata.zi -asctime.o: private.h tzfile.h +asctime.o: private.h date.o: private.h difftime.o: private.h -localtime.o: private.h tzfile.h tzdir.h -strftime.o: private.h tzfile.h -zdump.o: version.h -zic.o: private.h tzfile.h tzdir.h version.h +localtime.o: private.h tzdir.h tzfile.h +strftime.o: localtime.c private.h tzdir.h tzfile.h +zdump.o: private.h version.h +zic.o: private.h tzdir.h tzfile.h version.h .PHONY: ALL INSTALL all .PHONY: check check_mild check_time_t_alternatives diff --git a/contrib/tzcode/NEWS b/contrib/tzcode/NEWS index 83b8b8c8d39c..8c0771641ef0 100644 --- a/contrib/tzcode/NEWS +++ b/contrib/tzcode/NEWS @@ -1,5 +1,108 @@ News for the tz database +Release 2025b - 2025-03-22 13:40:46 -0700 + + Briefly: + New zone for Aysén Region in Chile which moves from -04/-03 to -03. + + Changes to future timestamps + + Chile's Aysén Region moves from -04/-03 to -03 year-round, joining + Magallanes Region. The region will not change its clocks on + 2025-04-05 at 24:00, diverging from America/Santiago and creating a + new zone America/Coyhaique. (Thanks to Yonathan Dossow.) Model + this as a change to standard offset effective 2025-03-20. + + Changes to past timestamps + + Iran switched from +04 to +0330 on 1978-11-10 at 24:00, not at + year end. (Thanks to Roozbeh Pournader.) + + Changes to code + + 'zic -l TIMEZONE -d . -l /some/other/file/system' no longer + attempts to create an incorrect symlink, and no longer has a + read buffer underflow. (Problem reported by Evgeniy Gorbanev.) + + +Release 2025a - 2025-01-15 10:47:24 -0800 + + Briefly: + Paraguay adopted permanent -03 starting spring 2024. + Improve pre-1991 data for the Philippines. + Etc/Unknown is now reserved. + + Changes to future timestamps + + Paraguay stopped changing its clocks after the spring-forward + transition on 2024-10-06, so it is now permanently at -03. + (Thanks to Heitor David Pinto and Even Scharning.) + This affects timestamps starting 2025-03-22, as well as the + obsolescent tm_isdst flags starting 2024-10-15. + + Changes to past timestamps + + Correct timestamps for the Philippines before 1900, and from 1937 + through 1990. (Thanks to P Chan for the heads-up and citations.) + This includes adjusting local mean time before 1899; fixing + transitions in September 1899, January 1937, and June 1954; adding + transitions in December 1941, November 1945, March and September + 1977, and May and July 1990; and removing incorrect transitions in + March and September 1978. + + Changes to data + + Add zone1970.tab lines for the Concordia and Eyre Bird Observatory + research stations. (Thanks to Derick Rethans and Jule Dabars.) + + Changes to code + + strftime %s now generates the correct numeric string even when the + represented number does not fit into time_t. This is better than + generating the numeric equivalent of (time_t) -1, as strftime did + in TZDB releases 96a (when %s was introduced) through 2020a and in + releases 2022b through 2024b. It is also better than failing and + returning 0, as strftime did in releases 2020b through 2022a. + + strftime now outputs an invalid conversion specifier as-is, + instead of eliding the leading '%', which confused debugging. + + An invalid TZ now generates the time zone abbreviation "-00", not + "UTC", to help the user see that an error has occurred. (Thanks + to Arthur David Olson for suggesting a "wrong result".) + + mktime and timeoff no longer incorrectly fail merely because a + struct tm component near INT_MIN or INT_MAX overflows when a + lower-order component carries into it. + + TZNAME_MAXIMUM, the maximum number of bytes in a proleptic TZ + string's time zone abbreviation, now defaults to 254 not 255. + This helps reduce the size of internal state from 25480 to 21384 + on common platforms. This change should not be a problem, as + nobody uses such long "abbreviations" and the longstanding tzcode + maximum was 16 until release 2023a. For those who prefer no + arbitrary limits, you can now specify TZNAME_MAXIMUM values up to + PTRDIFF_MAX, a limit forced by C anyway; formerly tzcode silently + misbehaved unless TZNAME_MAXIMUM was less than INT_MAX. + + tzset and related functions no longer leak a file descriptor if + another thread forks or execs at about the same time and if the + platform has O_CLOFORK and O_CLOEXEC respectively. Also, the + functions no longer let a TZif file become a controlling terminal. + + 'zdump -' now reads TZif data from /dev/stdin. + (From a question by Arthur David Olson.) + + Changes to documentation + + The name Etc/Unknown is now reserved: it will not be used by TZDB. + This is for compatibility with CLDR, which uses the string + "Etc/Unknown" for an unknown or invalid timezone. (Thanks to + Justin Grant, Mark Davis, and Guy Harris.) + + Cite Internet RFC 9636, which obsoletes RFC 8536 for TZif format. + + Release 2024b - 2024-09-04 12:27:47 -0700 Briefly: @@ -116,7 +219,7 @@ Release 2024b - 2024-09-04 12:27:47 -0700 Changes to commentary Commentary about historical transitions in Portugal and her former - colonies has been expanded with links to many relevant legislation. + colonies has been expanded with links to relevant legislation. (Thanks to Tim Parenti.) @@ -204,10 +307,10 @@ Release 2023d - 2023-12-21 20:02:24 -0800 changing its time zone from -01/+00 to -02/-01 at the same moment as the spring-forward transition. Its clocks will therefore not spring forward as previously scheduled. The time zone change - reverts to its common practice before 1981. + reverts to its common practice before 1981. (Thanks to Jule Dabars.) Fix predictions for DST transitions in Palestine in 2072-2075, - correcting a typo introduced in 2023a. + correcting a typo introduced in 2023a. (Thanks to Jule Dabars.) Changes to past and future timestamps diff --git a/contrib/tzcode/asctime.c b/contrib/tzcode/asctime.c index ebb90a1cc84d..1977a2272896 100644 --- a/contrib/tzcode/asctime.c +++ b/contrib/tzcode/asctime.c @@ -7,6 +7,7 @@ /* ** Avoid the temptation to punt entirely to strftime; +** strftime can behave badly when tm components are out of range, and ** the output of strftime is supposed to be locale specific ** whereas the output of asctime is supposed to be constant. */ @@ -18,27 +19,6 @@ #include "un-namespace.h" #include <stdio.h> -/* -** All years associated with 32-bit time_t values are exactly four digits long; -** some years associated with 64-bit time_t values are not. -** Vintage programs are coded for years that are always four digits long -** and may assume that the newline always lands in the same place. -** For years that are less than four digits, we pad the output with -** leading zeroes to get the newline in the traditional place. -** The -4 ensures that we get four characters of output even if -** we call a strftime variant that produces fewer characters for some years. -** This conforms to recent ISO C and POSIX standards, which say behavior -** is undefined when the year is less than 1000 or greater than 9999. -*/ -static char const ASCTIME_FMT[] = "%s %s%3d %.2d:%.2d:%.2d %-4s\n"; -/* -** For years that are more than four digits we put extra spaces before the year -** so that code trying to overwrite the newline won't end up overwriting -** a digit within a year and truncating the year (operating on the assumption -** that no output is better than wrong output). -*/ -static char const ASCTIME_FMT_B[] = "%s %s%3d %.2d:%.2d:%.2d %s\n"; - enum { STD_ASCTIME_BUF_SIZE = 26 }; /* ** Big enough for something such as @@ -52,14 +32,24 @@ enum { STD_ASCTIME_BUF_SIZE = 26 }; */ static char buf_asctime[2*3 + 5*INT_STRLEN_MAXIMUM(int) + 7 + 2 + 1 + 1]; -/* A similar buffer for ctime. - C89 requires that they be the same buffer. - This requirement was removed in C99, so support it only if requested, - as support is more likely to lead to bugs in badly written programs. */ -#if SUPPORT_C89 -# define buf_ctime buf_asctime -#else -static char buf_ctime[sizeof buf_asctime]; +/* On pre-C99 platforms, a snprintf substitute good enough for us. */ +#if !HAVE_SNPRINTF +# include <stdarg.h> +ATTRIBUTE_FORMAT((printf, 3, 4)) static int +my_snprintf(char *s, size_t size, char const *format, ...) +{ + int n; + va_list args; + char stackbuf[sizeof buf_asctime]; + va_start(args, format); + n = vsprintf(stackbuf, format, args); + va_end (args); + if (0 <= n && n < size) + memcpy (s, stackbuf, n + 1); + return n; +} +# undef snprintf +# define snprintf my_snprintf #endif /* Publish asctime_r and ctime_r only when supporting older POSIX. */ @@ -84,14 +74,19 @@ asctime_r(struct tm const *restrict timeptr, char *restrict buf) "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; - const char * wn; - const char * mn; - char year[INT_STRLEN_MAXIMUM(int) + 2]; - char result[sizeof buf_asctime]; + register const char * wn; + register const char * mn; + int year, mday, hour, min, sec; + long long_TM_YEAR_BASE = TM_YEAR_BASE; + size_t bufsize = (buf == buf_asctime + ? sizeof buf_asctime : STD_ASCTIME_BUF_SIZE); if (timeptr == NULL) { + strcpy(buf, "??? ??? ?? ??:??:?? ????\n"); + /* Set errno now, since strcpy might change it in + POSIX.1-2017 and earlier. */ errno = EINVAL; - return strcpy(buf, "??? ??? ?? ??:??:?? ????\n"); + return buf; } if (timeptr->tm_wday < 0 || timeptr->tm_wday >= DAYSPERWEEK) wn = "???"; @@ -99,25 +94,41 @@ asctime_r(struct tm const *restrict timeptr, char *restrict buf) if (timeptr->tm_mon < 0 || timeptr->tm_mon >= MONSPERYEAR) mn = "???"; else mn = mon_name[timeptr->tm_mon]; - /* - ** Use strftime's %Y to generate the year, to avoid overflow problems - ** when computing timeptr->tm_year + TM_YEAR_BASE. - ** Assume that strftime is unaffected by other out-of-range members - ** (e.g., timeptr->tm_mday) when processing "%Y". - */ - strftime(year, sizeof year, "%Y", timeptr); - /* - ** We avoid using snprintf since it's not available on all systems. - */ - sprintf(result, - ((strlen(year) <= 4) ? ASCTIME_FMT : ASCTIME_FMT_B), - wn, mn, - timeptr->tm_mday, timeptr->tm_hour, - timeptr->tm_min, timeptr->tm_sec, - year); - if (strlen(result) < STD_ASCTIME_BUF_SIZE - || buf == buf_ctime || buf == buf_asctime) - return strcpy(buf, result); + + year = timeptr->tm_year; + mday = timeptr->tm_mday; + hour = timeptr->tm_hour; + min = timeptr->tm_min; + sec = timeptr->tm_sec; + + /* Vintage programs are coded for years that are always four bytes long + and may assume that the newline always lands in the same place. + For years that are less than four bytes, pad the output with + leading zeroes to get the newline in the traditional place. + For years longer than four bytes, put extra spaces before the year + so that vintage code trying to overwrite the newline + won't overwrite a digit within a year and truncate the year, + using the principle that no output is better than wrong output. + This conforms to ISO C and POSIX standards, which say behavior + is undefined when the year is less than 1000 or greater than 9999. + + Also, avoid overflow when formatting tm_year + TM_YEAR_BASE. */ + + if ((year <= LONG_MAX - TM_YEAR_BASE + ? snprintf (buf, bufsize, + ((-999 - TM_YEAR_BASE <= year + && year <= 9999 - TM_YEAR_BASE) + ? "%s %s%3d %.2d:%.2d:%.2d %04ld\n" + : "%s %s%3d %.2d:%.2d:%.2d %ld\n"), + wn, mn, mday, hour, min, sec, + year + long_TM_YEAR_BASE) + : snprintf (buf, bufsize, + "%s %s%3d %.2d:%.2d:%.2d %d%d\n", + wn, mn, mday, hour, min, sec, + year / 10 + TM_YEAR_BASE / 10, + year % 10)) + < bufsize) + return buf; else { errno = EOVERFLOW; return NULL; @@ -142,5 +153,8 @@ ctime_r(const time_t *timep, char *buf) char * ctime(const time_t *timep) { - return ctime_r(timep, buf_ctime); + /* Do not call localtime_r, as C23 requires ctime to initialize the + static storage that localtime updates. */ + struct tm *tmp = localtime(timep); + return tmp ? asctime(tmp) : NULL; } diff --git a/contrib/tzcode/date.1 b/contrib/tzcode/date.1 index 01907bc76e2c..3a02e7c2e08a 100644 --- a/contrib/tzcode/date.1 +++ b/contrib/tzcode/date.1 @@ -6,15 +6,13 @@ date \- show and set date and time .SH SYNOPSIS .if n .nh .if n .na -.ie \n(.g .ds - \f(CR-\fP -.el .ds - \- .B date [ -.B \*-u +.B \-u ] [ -.B \*-c +.B \-c ] [ -.B \*-r +.B \-r .I seconds ] [ .BI + format @@ -35,7 +33,7 @@ command without arguments writes the date and time to the standard output in the form .ce 1 -Wed Mar 8 14:54:40 EST 1989 +Sat Mar 8 14:54:40 EST 2025 .br with .B EST @@ -49,99 +47,24 @@ If a command-line argument starts with a plus sign (\c .q "\fB+\fP" ), the rest of the argument is used as a .I format -that controls what appears in the output. -In the format, when a percent sign (\c -.q "\fB%\fP" -appears, -it and the character after it are not output, -but rather identify part of the date or time -to be output in a particular way -(or identify a special character to output): -.nf -.sp -.if t .in +.5i -.if n .in +2 -.ta \w'%M\0\0'u +\w'Wed Mar 8 14:54:40 EST 1989\0\0'u - Sample output Explanation -%a Wed Abbreviated weekday name* -%A Wednesday Full weekday name* -%b Mar Abbreviated month name* -%B March Full month name* -%c Wed Mar 08 14:54:40 1989 Date and time* -%C 19 Century -%d 08 Day of month (always two digits) -%D 03/08/89 Month/day/year (eight characters) -%e 8 Day of month (leading zero blanked) -%h Mar Abbreviated month name* -%H 14 24-hour-clock hour (two digits) -%I 02 12-hour-clock hour (two digits) -%j 067 Julian day number (three digits) -%k 2 12-hour-clock hour (leading zero blanked) -%l 14 24-hour-clock hour (leading zero blanked) -%m 03 Month number (two digits) -%M 54 Minute (two digits) -%n \\n newline character -%p PM AM/PM designation -%r 02:54:40 PM Hour:minute:second AM/PM designation -%R 14:54 Hour:minute -%S 40 Second (two digits) -%t \\t tab character -%T 14:54:40 Hour:minute:second -%U 10 Sunday-based week number (two digits) -%w 3 Day number (one digit, Sunday is 0) -%W 10 Monday-based week number (two digits) -%x 03/08/89 Date* -%X 14:54:40 Time* -%y 89 Last two digits of year -%Y 1989 Year in full -%z -0500 Numeric time zone -%Z EST Time zone abbreviation -%+ Wed Mar 8 14:54:40 EST 1989 Default output format* -.if t .in -.5i -.if n .in -2 -* The exact output depends on the locale. -.sp -.fi -If a character other than one of those shown above appears after -a percent sign in the format, -that following character is output. -All other characters in the format are copied unchanged to the output; -a newline character is always added at the end of the output. -.PP -In Sunday-based week numbering, -the first Sunday of the year begins week 1; -days preceding it are part of -.q "week 0" . -In Monday-based week numbering, -the first Monday of the year begins week 1. -.PP -To set the date, use a command line argument with one of the following forms: -.nf -.if t .in +.5i -.if n .in +2 -.ta \w'198903081454\0'u -1454 24-hour-clock hours (first two digits) and minutes -081454 Month day (first two digits), hours, and minutes -03081454 Month (two digits, January is 01), month day, hours, minutes -8903081454 Year, month, month day, hours, minutes -0308145489 Month, month day, hours, minutes, year - (on System V-compatible systems) -030814541989 Month, month day, hours, minutes, four-digit year -198903081454 Four-digit year, month, month day, hours, minutes -.if t .in -.5i -.if n .in -2 -.fi -If the century, year, month, or month day is not given, -the current value is used. -Any of the above forms may be followed by a period and two digits that give -the seconds part of the new time; if no seconds are given, zero is assumed. +that is processed by +.BR strftime (3) +to determine what to output; +a newline character is appended. +For example, the shell command: +.ce 1 +date +"%Y\-%m\-%d %H:%M:%S %z" +.br +outputs a line like +.q "2025\-03\-08 14:54:40 \-0500" +instead. .PP These options are available: .TP -.BR \*-u " or " \*-c +.BR \-u " or " \-c Use Universal Time when setting and showing the date and time. .TP -.BI "\*-r " seconds +.BI "\-r " seconds Output the date that corresponds to .I seconds past the epoch of 1970-01-01 00:00:00 UTC, where @@ -149,16 +72,13 @@ past the epoch of 1970-01-01 00:00:00 UTC, where should be an integer, either decimal, octal (leading 0), or hexadecimal (leading 0x), preceded by an optional sign. .SH FILES -.ta \w'/usr/share/zoneinfo/posixrules\0\0'u +.ta \w'/usr/share/zoneinfo/Etc/UTC\0\0'u /etc/localtime local timezone file .br /usr/lib/locale/\f2L\fP/LC_TIME description of time locale \f2L\fP .br /usr/share/zoneinfo timezone directory .br -/usr/share/zoneinfo/posixrules default DST rules (obsolete) -.br -/usr/share/zoneinfo/GMT for UTC leap seconds -.PP -If /usr/share/zoneinfo/GMT is absent, -UTC leap seconds are loaded from /usr/share/zoneinfo/GMT0 if present. +/usr/share/zoneinfo/Etc/UTC for UTC leap seconds +.SH SEE ALSO +.BR strftime (3). diff --git a/contrib/tzcode/localtime.c b/contrib/tzcode/localtime.c index a6ec3d8e4e21..15afeeecb6d0 100644 --- a/contrib/tzcode/localtime.c +++ b/contrib/tzcode/localtime.c @@ -13,42 +13,116 @@ /*LINTLIBRARY*/ #define LOCALTIME_IMPLEMENTATION +#ifdef __FreeBSD__ #include "namespace.h" +#include <pthread.h> +#endif /* __FreeBSD__ */ #ifdef DETECT_TZ_CHANGES -#ifndef DETECT_TZ_CHANGES_INTERVAL -#define DETECT_TZ_CHANGES_INTERVAL 61 -#endif +# ifndef DETECT_TZ_CHANGES_INTERVAL +# define DETECT_TZ_CHANGES_INTERVAL 61 +# endif int __tz_change_interval = DETECT_TZ_CHANGES_INTERVAL; -#include <sys/stat.h> -#endif -#include <fcntl.h> -#if THREAD_SAFE -#include <pthread.h> -#endif +# include <sys/stat.h> +#endif /* DETECT_TZ_CHANGES */ #include "private.h" -#include "un-namespace.h" #include "tzdir.h" #include "tzfile.h" - +#include <fcntl.h> +#ifdef __FreeBSD__ #include "libc_private.h" +#include "un-namespace.h" +#endif /* __FreeBSD__ */ + +#if HAVE_SYS_STAT_H +# include <sys/stat.h> +#endif +#if !defined S_ISREG && defined S_IFREG +/* Ancient UNIX or recent MS-Windows. */ +# define S_ISREG(mode) (((mode) & S_IFMT) == S_IFREG) +#endif #if defined THREAD_SAFE && THREAD_SAFE +# include <pthread.h> +#ifdef __FreeBSD__ +# define pthread_mutex_lock(l) (__isthreaded ? _pthread_mutex_lock(l) : 0) +# define pthread_mutex_unlock(l) (__isthreaded ? _pthread_mutex_unlock(l) : 0) +#endif /* __FreeBSD__ */ static pthread_mutex_t locallock = PTHREAD_MUTEX_INITIALIZER; -static int lock(void) { - if (__isthreaded) - return _pthread_mutex_lock(&locallock); - return 0; -} -static void unlock(void) { - if (__isthreaded) - _pthread_mutex_unlock(&locallock); -} +static int lock(void) { return pthread_mutex_lock(&locallock); } +static void unlock(void) { pthread_mutex_unlock(&locallock); } #else static int lock(void) { return 0; } static void unlock(void) { } #endif +/* Unless intptr_t is missing, pacify gcc -Wcast-qual on char const * exprs. + Use this carefully, as the casts disable type checking. + This is a macro so that it can be used in static initializers. */ +#ifdef INTPTR_MAX +# define UNCONST(a) ((char *) (intptr_t) (a)) +#else +# define UNCONST(a) ((char *) (a)) +#endif + +/* A signed type wider than int, so that we can add 1900 + tm_mon/12 to tm_year + without overflow. The static_assert checks that it is indeed wider + than int; if this fails on your platform please let us know. */ +#if INT_MAX < LONG_MAX +typedef long iinntt; +# define IINNTT_MIN LONG_MIN +# define IINNTT_MAX LONG_MAX +#elif INT_MAX < LLONG_MAX +typedef long long iinntt; +# define IINNTT_MIN LLONG_MIN +# define IINNTT_MAX LLONG_MAX +#else +typedef intmax_t iinntt; +# define IINNTT_MIN INTMAX_MIN +# define IINNTT_MAX INTMAX_MAX +#endif +static_assert(IINNTT_MIN < INT_MIN && INT_MAX < IINNTT_MAX); + +/* On platforms where offtime or mktime might overflow, + strftime.c defines USE_TIMEX_T to be true and includes us. + This tells us to #define time_t to an internal type timex_t that is + wide enough so that strftime %s never suffers from integer overflow, + and to #define offtime (if TM_GMTOFF is defined) or mktime (otherwise) + to a static function that returns the redefined time_t. + It also tells us to define only data and code needed + to support the offtime or mktime variant. */ +#ifndef USE_TIMEX_T +# define USE_TIMEX_T false +#endif +#if USE_TIMEX_T +# undef TIME_T_MIN +# undef TIME_T_MAX +# undef time_t +# define time_t timex_t +# if MKTIME_FITS_IN(LONG_MIN, LONG_MAX) +typedef long timex_t; +# define TIME_T_MIN LONG_MIN +# define TIME_T_MAX LONG_MAX +# elif MKTIME_FITS_IN(LLONG_MIN, LLONG_MAX) +typedef long long timex_t; +# define TIME_T_MIN LLONG_MIN +# define TIME_T_MAX LLONG_MAX +# else +typedef intmax_t timex_t; +# define TIME_T_MIN INTMAX_MIN +# define TIME_T_MAX INTMAX_MAX +# endif + +# ifdef TM_GMTOFF +# undef timeoff +# define timeoff timex_timeoff +# undef EXTERN_TIMEOFF +# else +# undef mktime +# define mktime timex_mktime +# endif +#endif + #ifndef TZ_ABBR_CHAR_SET # define TZ_ABBR_CHAR_SET \ "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789 :+-._" @@ -58,12 +132,23 @@ static void unlock(void) { } # define TZ_ABBR_ERR_CHAR '_' #endif /* !defined TZ_ABBR_ERR_CHAR */ -/* -** Support non-POSIX platforms that distinguish between text and binary files. -*/ +/* Port to platforms that lack some O_* flags. Unless otherwise + specified, the flags are standardized by POSIX. */ #ifndef O_BINARY -# define O_BINARY 0 +# define O_BINARY 0 /* MS-Windows */ +#endif +#ifndef O_CLOEXEC +# define O_CLOEXEC 0 +#endif +#ifndef O_CLOFORK +# define O_CLOFORK 0 +#endif +#ifndef O_IGNORE_CTTY +# define O_IGNORE_CTTY 0 /* GNU/Hurd */ +#endif +#ifndef O_NOCTTY +# define O_NOCTTY 0 #endif #ifndef WILDABBR @@ -92,7 +177,10 @@ static void unlock(void) { } static const char wildabbr[] = WILDABBR; static char const etc_utc[] = "Etc/UTC"; + +#if !USE_TIMEX_T || defined TM_ZONE || !defined TM_GMTOFF static char const *utc = etc_utc + sizeof "Etc/" - 1; +#endif /* ** The DST rules to use if TZ has no rules and we can't load TZDEFRULES. @@ -104,10 +192,31 @@ static char const *utc = etc_utc + sizeof "Etc/" - 1; # define TZDEFRULESTRING ",M3.2.0,M11.1.0" #endif +/* Limit to time zone abbreviation length in proleptic TZ strings. + This is distinct from TZ_MAX_CHARS, which limits TZif file contents. + It defaults to 254, not 255, so that desigidx_type can be an unsigned char. + unsigned char suffices for TZif files, so the only reason to increase + TZNAME_MAXIMUM is to support TZ strings specifying abbreviations + longer than 254 bytes. There is little reason to do that, though, + as strings that long are hardly "abbreviations". */ +#ifndef TZNAME_MAXIMUM +# define TZNAME_MAXIMUM 254 +#endif + +#if TZNAME_MAXIMUM < UCHAR_MAX +typedef unsigned char desigidx_type; +#elif TZNAME_MAXIMUM < INT_MAX +typedef int desigidx_type; +#elif TZNAME_MAXIMUM < PTRDIFF_MAX +typedef ptrdiff_t desigidx_type; +#else +# error "TZNAME_MAXIMUM too large" +#endif + struct ttinfo { /* time type information */ - int_fast32_t tt_utoff; /* UT offset in seconds */ + int_least32_t tt_utoff; /* UT offset in seconds */ + desigidx_type tt_desigidx; /* abbreviation list index */ bool tt_isdst; /* used to set tm_isdst */ - int tt_desigidx; /* abbreviation list index */ bool tt_ttisstd; /* transition is std time */ bool tt_ttisut; /* transition is UT */ }; @@ -126,12 +235,6 @@ static char const UNSPEC[] = "-00"; for ttunspecified to work without crashing. */ enum { CHARS_EXTRA = max(sizeof UNSPEC, 2) - 1 }; -/* Limit to time zone abbreviation length in proleptic TZ strings. - This is distinct from TZ_MAX_CHARS, which limits TZif file contents. */ -#ifndef TZNAME_MAXIMUM -# define TZNAME_MAXIMUM 255 -#endif - /* A representation of the contents of a TZif file. Ideally this would have no size limits; the following sizes should suffice for practical use. This struct should not be too large, as instances @@ -166,12 +269,14 @@ struct rule { int_fast32_t r_time; /* transition time of rule */ }; +#ifdef __FreeBSD__ +static void tzset_unlocked_name(char const *); +#endif /* __FreeBSD__ */ static struct tm *gmtsub(struct state const *, time_t const *, int_fast32_t, struct tm *); static bool increment_overflow(int *, int); static bool increment_overflow_time(time_t *, int_fast32_t); static int_fast32_t leapcorr(struct state const *, time_t); -static bool normalize_overflow32(int_fast32_t *, int *, int); static struct tm *timesub(time_t const *, int_fast32_t, struct state const *, struct tm *); static bool tzparse(char const *, struct state *, struct state const *); @@ -192,9 +297,11 @@ static struct state *const gmtptr = &gmtmem; # define TZ_STRLEN_MAX 255 #endif /* !defined TZ_STRLEN_MAX */ +#if !USE_TIMEX_T || !defined TM_GMTOFF static char lcl_TZname[TZ_STRLEN_MAX + 1]; static int lcl_is_set; - +#endif +#ifdef __FreeBSD__ static pthread_once_t gmt_once = PTHREAD_ONCE_INIT; static pthread_once_t gmtime_once = PTHREAD_ONCE_INIT; static pthread_key_t gmtime_key; @@ -205,6 +312,7 @@ static int offtime_key_error; static pthread_once_t localtime_once = PTHREAD_ONCE_INIT; static pthread_key_t localtime_key; static int localtime_key_error; +#endif /* __FreeBSD__ */ /* ** Section 4.12.3 of X3.159-1989 requires that @@ -218,27 +326,29 @@ static int localtime_key_error; ** trigger latent bugs in programs. */ -#if SUPPORT_C89 +#if !USE_TIMEX_T + +# if SUPPORT_C89 static struct tm tm; #endif -#if 2 <= HAVE_TZNAME + TZ_TIME_T -char * tzname[2] = { - (char *) wildabbr, - (char *) wildabbr -}; -#endif -#if 2 <= USG_COMPAT + TZ_TIME_T +# if 2 <= HAVE_TZNAME + TZ_TIME_T +char *tzname[2] = { UNCONST(wildabbr), UNCONST(wildabbr) }; +# endif +# if 2 <= USG_COMPAT + TZ_TIME_T long timezone; int daylight; -#endif -#if 2 <= ALTZONE + TZ_TIME_T +# endif +# if 2 <= ALTZONE + TZ_TIME_T long altzone; +# endif + #endif /* Initialize *S to a value based on UTOFF, ISDST, and DESIGIDX. */ static void -init_ttinfo(struct ttinfo *s, int_fast32_t utoff, bool isdst, int desigidx) +init_ttinfo(struct ttinfo *s, int_fast32_t utoff, bool isdst, + desigidx_type desigidx) { s->tt_utoff = utoff; s->tt_isdst = isdst; @@ -302,20 +412,22 @@ detzcode64(const char *const codep) return result; } +#if !USE_TIMEX_T || !defined TM_GMTOFF + static void update_tzname_etc(struct state const *sp, struct ttinfo const *ttisp) { -#if HAVE_TZNAME - tzname[ttisp->tt_isdst] = (char *) &sp->chars[ttisp->tt_desigidx]; -#endif -#if USG_COMPAT +# if HAVE_TZNAME + tzname[ttisp->tt_isdst] = UNCONST(&sp->chars[ttisp->tt_desigidx]); +# endif +# if USG_COMPAT if (!ttisp->tt_isdst) timezone = - ttisp->tt_utoff; -#endif -#if ALTZONE +# endif +# if ALTZONE if (ttisp->tt_isdst) altzone = - ttisp->tt_utoff; -#endif +# endif } /* If STDDST_MASK indicates that SP's TYPE provides useful info, @@ -346,18 +458,18 @@ settzname(void) When STDDST_MASK becomes zero we can stop looking. */ int stddst_mask = 0; -#if HAVE_TZNAME - tzname[0] = tzname[1] = (char *) (sp ? wildabbr : utc); +# if HAVE_TZNAME + tzname[0] = tzname[1] = UNCONST(sp ? wildabbr : utc); stddst_mask = 3; -#endif -#if USG_COMPAT +# endif +# if USG_COMPAT timezone = 0; stddst_mask = 3; -#endif -#if ALTZONE +# endif +# if ALTZONE altzone = 0; stddst_mask |= 2; -#endif +# endif /* ** And to get the latest time zone abbreviations into tzname. . . */ @@ -367,9 +479,9 @@ settzname(void) for (i = sp->typecnt - 1; stddst_mask && 0 <= i; i--) stddst_mask = may_update_tzname_etc(stddst_mask, sp, i); } -#if USG_COMPAT +# if USG_COMPAT daylight = stddst_mask >> 1 ^ 1; -#endif +# endif } /* Replace bogus characters in time zone abbreviations. @@ -396,21 +508,24 @@ scrub_abbrs(struct state *sp) return 0; } +#endif + #ifdef DETECT_TZ_CHANGES /* - * Determine if there's a change in the timezone since the last time we checked. + * Check whether either the time zone name or the file it refers to has + * changed since the last time we checked. * Returns: -1 on error - * 0 if the timezone has not changed - * 1 if the timezone has changed + * 0 if the time zone has not changed + * 1 if the time zone has changed */ static int -change_in_tz(const char *name) +tzfile_changed(const char *name, int fd) { static char old_name[PATH_MAX]; static struct stat old_sb; struct stat sb; - if (stat(name, &sb) != 0) + if (_fstat(fd, &sb) != 0) return -1; if (strcmp(name, old_name) != 0) { @@ -429,9 +544,7 @@ change_in_tz(const char *name) return 0; } -#else /* !DETECT_TZ_CHANGES */ -#define change_in_tz(X) 1 -#endif /* !DETECT_TZ_CHANGES */ +#endif /* DETECT_TZ_CHANGES */ /* Input buffer for data read from a compiled tz file. */ union input_buffer { @@ -444,8 +557,10 @@ union input_buffer { + 4 * TZ_MAX_TIMES]; }; +#ifndef __FreeBSD__ /* TZDIR with a trailing '/' rather than a trailing '\0'. */ static char const tzdirslash[sizeof TZDIR] = TZDIR "/"; +#endif /* !__FreeBSD__ */ /* Local storage needed for 'tzloadbody'. */ union local_storage { @@ -458,6 +573,7 @@ union local_storage { struct state st; } u; +#ifndef __FreeBSD__ /* The name of the file to be opened. Ideally this would have no size limits, to support arbitrarily long Zone names. Limiting Zone names to 1024 bytes should suffice for practical use. @@ -465,19 +581,31 @@ union local_storage { file_analysis as that struct is allocated anyway, as the other union member. */ char fullname[max(sizeof(struct file_analysis), sizeof tzdirslash + 1024)]; +#endif /* !__FreeBSD__ */ }; -/* Load tz data from the file named NAME into *SP. Read extended - format if DOEXTEND. Use *LSP for temporary storage. Return 0 on +/* These tzload flags can be ORed together, and fit into 'char'. */ +enum { TZLOAD_FROMENV = 1 }; /* The TZ string came from the environment. */ +enum { TZLOAD_TZSTRING = 2 }; /* Read any newline-surrounded TZ string. */ + +/* Load tz data from the file named NAME into *SP. Respect TZLOADFLAGS. + Use *LSP for temporary storage. Return 0 on success, an errno value on failure. */ static int -tzloadbody(char const *name, struct state *sp, bool doextend, +tzloadbody(char const *name, struct state *sp, char tzloadflags, union local_storage *lsp) { register int i; register int fid; register int stored; register ssize_t nread; +#ifdef __FreeBSD__ + struct stat sb; + const char *relname; + int dd, serrno; +#else /* !__FreeBSD__ */ + register bool doaccess; +#endif /* !__FreeBSD__ */ register union input_buffer *up = &lsp->u.u; register int tzheadsize = sizeof(struct tzhead); @@ -487,11 +615,21 @@ tzloadbody(char const *name, struct state *sp, bool doextend, name = TZDEFAULT; if (! name) return EINVAL; + tzloadflags &= ~TZLOAD_FROMENV; } if (name[0] == ':') ++name; - if (name[0] != '/') { +#ifndef __FreeBSD__ +#ifdef SUPPRESS_TZDIR + /* Do not prepend TZDIR. This is intended for specialized + applications only, due to its security implications. */ + doaccess = true; +#else + doaccess = name[0] == '/'; +#endif + if (!doaccess) { + char const *dot; if (sizeof lsp->fullname - sizeof tzdirslash <= strlen(name)) return ENAMETOOLONG; @@ -501,27 +639,91 @@ tzloadbody(char const *name, struct state *sp, bool doextend, memcpy(lsp->fullname, tzdirslash, sizeof tzdirslash); strcpy(lsp->fullname + sizeof tzdirslash, name); + /* Set doaccess if NAME contains a ".." file name + component, as such a name could read a file outside + the TZDIR virtual subtree. */ + for (dot = name; (dot = strchr(dot, '.')); dot++) + if ((dot == name || dot[-1] == '/') && dot[1] == '.' + && (dot[2] == '/' || !dot[2])) { + doaccess = true; + break; + } + name = lsp->fullname; } - if (doextend) { - /* - * Detect if the timezone file has changed. Check - * 'doextend' to ignore TZDEFRULES; the change_in_tz() - * function can only keep state for a single file. - */ - switch (change_in_tz(name)) { - case -1: - return errno; - case 0: - return 0; - case 1: - break; - } + if (doaccess && (tzloadflags & TZLOAD_FROMENV)) { + /* Check for security violations and for devices whose mere + opening could have unwanted side effects. Although these + checks are racy, they're better than nothing and there is + no portable way to fix the races. */ + if (access(name, R_OK) < 0) + return errno; +#ifdef S_ISREG + { + struct stat st; + if (stat(name, &st) < 0) + return errno; + if (!S_ISREG(st.st_mode)) + return EINVAL; + } +#endif + } + fid = _open(name, (O_RDONLY | O_BINARY | O_CLOEXEC | O_CLOFORK + | O_IGNORE_CTTY | O_NOCTTY)); +#else /* __FreeBSD__ */ + if ((tzloadflags & TZLOAD_FROMENV) && strcmp(name, TZDEFAULT) == 0) + tzloadflags &= ~TZLOAD_FROMENV; + relname = name; + if (strncmp(relname, TZDIR "/", strlen(TZDIR) + 1) == 0) + relname += strlen(TZDIR) + 1; + dd = _open(TZDIR, O_DIRECTORY | O_RDONLY); + if ((tzloadflags & TZLOAD_FROMENV) && issetugid()) { + if (dd < 0) + return errno; + if (fstatat(dd, name, &sb, AT_RESOLVE_BENEATH) < 0) { + fid = -1; + } else if (!S_ISREG(sb.st_mode)) { + fid = -1; + errno = EINVAL; + } else { + fid = _openat(dd, relname, O_RDONLY | O_BINARY, AT_RESOLVE_BENEATH); + } + } else { + if (dd < 0) { + relname = name; + dd = AT_FDCWD; + } + fid = _openat(dd, relname, O_RDONLY | O_BINARY, 0); + } + if (dd != AT_FDCWD && dd >= 0) { + serrno = errno; + _close(dd); + errno = serrno; } - fid = _open(name, O_RDONLY | O_BINARY); +#endif /* __FreeBSD__ */ if (fid < 0) return errno; +#ifdef DETECT_TZ_CHANGES + if (tzloadflags) { + /* + * Detect if the timezone file has changed. Check tzloadflags + * to ignore TZDEFRULES; the tzfile_changed() function can only + * keep state for a single file. + */ + switch (tzfile_changed(name, fid)) { + case -1: + serrno = errno; + _close(fid); + return serrno; + case 0: + _close(fid); + return 0; + case 1: + break; + } + } +#endif /* DETECT_TZ_CHANGES */ nread = _read(fid, up->buf, sizeof up->buf); if (nread < tzheadsize) { int err = nread < 0 ? errno : EINVAL; @@ -645,7 +847,7 @@ tzloadbody(char const *name, struct state *sp, bool doextend, correction must differ from the previous one's by 1 second or less, except that the first correction can be any value; these requirements are more generous than - RFC 8536, to allow future RFC extensions. */ + RFC 9636, to allow future RFC extensions. */ if (! (i == 0 || (prevcorr < corr ? corr == prevcorr + 1 @@ -696,7 +898,7 @@ tzloadbody(char const *name, struct state *sp, bool doextend, if (!version) break; } - if (doextend && nread > 2 && + if ((tzloadflags & TZLOAD_TZSTRING) && nread > 2 && up->buf[0] == '\n' && up->buf[nread - 1] == '\n' && sp->typecnt + 2 <= TZ_MAX_TYPES) { struct state *ts = &lsp->u.st; @@ -771,23 +973,23 @@ tzloadbody(char const *name, struct state *sp, bool doextend, return 0; } -/* Load tz data from the file named NAME into *SP. Read extended - format if DOEXTEND. Return 0 on success, an errno value on failure. */ +/* Load tz data from the file named NAME into *SP. Respect TZLOADFLAGS. + Return 0 on success, an errno value on failure. */ static int -tzload(char const *name, struct state *sp, bool doextend) +tzload(char const *name, struct state *sp, char tzloadflags) { #ifdef ALL_STATE union local_storage *lsp = malloc(sizeof *lsp); if (!lsp) { return HAVE_MALLOC_ERRNO ? errno : ENOMEM; } else { - int err = tzloadbody(name, sp, doextend, lsp); + int err = tzloadbody(name, sp, tzloadflags, lsp); free(lsp); return err; } #else union local_storage ls; - return tzloadbody(name, sp, doextend, &ls); + return tzloadbody(name, sp, tzloadflags, &ls); #endif } @@ -1128,7 +1330,7 @@ tzparse(const char *name, struct state *sp, struct state const *basep) sp->leapcnt = basep->leapcnt; memcpy(sp->lsis, basep->lsis, sp->leapcnt * sizeof *sp->lsis); } else { - load_ok = tzload(TZDEFRULES, sp, false) == 0; + load_ok = tzload(TZDEFRULES, sp, 0) == 0; if (!load_ok) sp->leapcnt = 0; /* So, we're off a little. */ } @@ -1365,13 +1567,16 @@ tzparse(const char *name, struct state *sp, struct state const *basep) static void gmtload(struct state *const sp) { - if (tzload(etc_utc, sp, true) != 0) + if (tzload(etc_utc, sp, TZLOAD_TZSTRING) != 0) tzparse("UTC0", sp, NULL); } #ifdef DETECT_TZ_CHANGES +/* + * Check if the time zone data we have is still fresh. + */ static int -recheck_tzdata() +tzdata_is_fresh(void) { static time_t last_checked; struct timespec now; @@ -1387,14 +1592,15 @@ recheck_tzdata() return 0; } -#else /* !DETECT_TZ_CHANGES */ -#define recheck_tzdata() 0 -#endif /* !DETECT_TZ_CHANGES */ +#endif /* DETECT_TZ_CHANGES */ + +#if !USE_TIMEX_T || !defined TM_GMTOFF /* Initialize *SP to a value appropriate for the TZ setting NAME. + Respect TZLOADFLAGS. Return 0 on success, an errno value on failure. */ static int -zoneinit(struct state *sp, char const *name) +zoneinit(struct state *sp, char const *name, char tzloadflags) { if (name && ! name[0]) { /* @@ -1409,7 +1615,7 @@ zoneinit(struct state *sp, char const *name) strcpy(sp->chars, utc); return 0; } else { - int err = tzload(name, sp, true); + int err = tzload(name, sp, tzloadflags); if (err != 0 && name && name[0] != ':' && tzparse(name, sp, NULL)) err = 0; if (err == 0) @@ -1419,22 +1625,34 @@ zoneinit(struct state *sp, char const *name) } static void +tzset_unlocked(void) +{ + char const *name = getenv("TZ"); +#ifdef __FreeBSD__ + tzset_unlocked_name(name); +} +static void tzset_unlocked_name(char const *name) { +#endif struct state *sp = lclptr; int lcl = name ? strlen(name) < sizeof lcl_TZname : -1; if (lcl < 0 ? lcl_is_set < 0 : 0 < lcl_is_set && strcmp(lcl_TZname, name) == 0) - if (recheck_tzdata() == 0) - return; -#ifdef ALL_STATE +#ifdef DETECT_TZ_CHANGES + if (tzdata_is_fresh() == 0) +#endif /* DETECT_TZ_CHANGES */ + return; +# ifdef ALL_STATE if (! sp) lclptr = sp = malloc(sizeof *lclptr); -#endif /* defined ALL_STATE */ +# endif if (sp) { - if (zoneinit(sp, name) != 0) - zoneinit(sp, ""); + if (zoneinit(sp, name, TZLOAD_FROMENV | TZLOAD_TZSTRING) != 0) { + zoneinit(sp, "", 0); + strcpy(sp->chars, UNSPEC); + } if (0 < lcl) strcpy(lcl_TZname, name); } @@ -1442,12 +1660,9 @@ tzset_unlocked_name(char const *name) lcl_is_set = lcl; } -static void -tzset_unlocked(void) -{ - tzset_unlocked_name(getenv("TZ")); -} +#endif +#if !USE_TIMEX_T void tzset(void) { @@ -1456,7 +1671,9 @@ tzset(void) tzset_unlocked(); unlock(); } +#endif +#ifdef __FreeBSD__ void freebsd13_tzsetwall(void) { @@ -1468,7 +1685,7 @@ freebsd13_tzsetwall(void) __sym_compat(tzsetwall, freebsd13_tzsetwall, FBSD_1.0); __warn_references(tzsetwall, "warning: tzsetwall() is deprecated, use tzset() instead."); - +#endif /* __FreeBSD__ */ static void gmtcheck(void) { @@ -1485,15 +1702,18 @@ gmtcheck(void) } unlock(); } +#ifdef __FreeBSD__ +#define gmtcheck() _once(&gmt_once, gmtcheck) +#endif -#if NETBSD_INSPIRED +#if NETBSD_INSPIRED && !USE_TIMEX_T timezone_t tzalloc(char const *name) { timezone_t sp = malloc(sizeof *sp); if (sp) { - int err = zoneinit(sp, name); + int err = zoneinit(sp, name, TZLOAD_TZSTRING); if (err != 0) { free(sp); errno = err; @@ -1522,6 +1742,8 @@ tzfree(timezone_t sp) #endif +#if !USE_TIMEX_T || !defined TM_GMTOFF + /* ** The easy way to behave "as if no library function calls" localtime ** is to not call it, so we drop its guts into "localsub", which can be @@ -1576,14 +1798,14 @@ localsub(struct state const *sp, time_t const *timep, int_fast32_t setname, return NULL; /* "cannot happen" */ result = localsub(sp, &newt, setname, tmp); if (result) { -#if defined ckd_add && defined ckd_sub +# if defined ckd_add && defined ckd_sub if (t < sp->ats[0] ? ckd_sub(&result->tm_year, result->tm_year, years) : ckd_add(&result->tm_year, result->tm_year, years)) return NULL; -#else +# else register int_fast64_t newy; newy = result->tm_year; @@ -1593,7 +1815,7 @@ localsub(struct state const *sp, time_t const *timep, int_fast32_t setname, if (! (INT_MIN <= newy && newy <= INT_MAX)) return NULL; result->tm_year = newy; -#endif +# endif } return result; } @@ -1622,25 +1844,26 @@ localsub(struct state const *sp, time_t const *timep, int_fast32_t setname, result = timesub(&t, ttisp->tt_utoff, sp, tmp); if (result) { result->tm_isdst = ttisp->tt_isdst; -#ifdef TM_ZONE - result->TM_ZONE = (char *) &sp->chars[ttisp->tt_desigidx]; -#endif /* defined TM_ZONE */ +# ifdef TM_ZONE + result->TM_ZONE = UNCONST(&sp->chars[ttisp->tt_desigidx]); +# endif if (setname) update_tzname_etc(sp, ttisp); } return result; } +#endif -#if NETBSD_INSPIRED +#if !USE_TIMEX_T +# if NETBSD_INSPIRED struct tm * localtime_rz(struct state *restrict sp, time_t const *restrict timep, struct tm *restrict tmp) { return localsub(sp, timep, 0, tmp); } - -#endif +# endif static struct tm * localtime_tzset(time_t const *timep, struct tm *tmp, bool setname) @@ -1652,45 +1875,47 @@ localtime_tzset(time_t const *timep, struct tm *tmp, bool setname) } #ifndef DETECT_TZ_CHANGES if (setname || !lcl_is_set) -#endif +#endif /* DETECT_TZ_CHANGES */ tzset_unlocked(); tmp = localsub(lclptr, timep, setname, tmp); unlock(); return tmp; } +#ifdef __FreeBSD__ static void localtime_key_init(void) { - - localtime_key_error = _pthread_key_create(&localtime_key, free); + localtime_key_error = _pthread_key_create(&localtime_key, free); } - +#endif /* __FreeBSD__ */ struct tm * localtime(const time_t *timep) { -#if !SUPPORT_C89 - static struct tm tm; -#endif - struct tm *p_tm = &tm; - - if (__isthreaded != 0) { - _pthread_once(&localtime_once, localtime_key_init); - if (localtime_key_error != 0) { - errno = localtime_key_error; - return (NULL); - } - if ((p_tm = _pthread_getspecific(localtime_key)) == NULL) { - if ((p_tm = malloc(sizeof(*p_tm))) == NULL) { - return (NULL); - } - if (_pthread_setspecific(localtime_key, p_tm) != 0) { - free(p_tm); - return (NULL); - } - } - } - return localtime_tzset(timep, p_tm, true); +# if !SUPPORT_C89 + static struct tm tm; +# endif +#ifdef __FreeBSD__ + struct tm *p_tm = &tm; + + if (__isthreaded != 0) { + _pthread_once(&localtime_once, localtime_key_init); + if (localtime_key_error != 0) { + errno = localtime_key_error; + return (NULL); + } + if ((p_tm = _pthread_getspecific(localtime_key)) == NULL) { + if ((p_tm = malloc(sizeof(*p_tm))) == NULL) { + return (NULL); + } + if (_pthread_setspecific(localtime_key, p_tm) != 0) { + free(p_tm); + return (NULL); + } + } + } +#endif /* __FreeBSD__ */ + return localtime_tzset(timep, p_tm, true); } struct tm * @@ -1698,6 +1923,7 @@ localtime_r(const time_t *restrict timep, struct tm *restrict tmp) { return localtime_tzset(timep, tmp, false); } +#endif /* ** gmtsub is to gmtime as localsub is to localtime. @@ -1716,12 +1942,14 @@ gmtsub(ATTRIBUTE_MAYBE_UNUSED struct state const *sp, time_t const *timep, ** "+xx" or "-xx" if offset is non-zero, ** but this is no time for a treasure hunt. */ - tmp->TM_ZONE = ((char *) - (offset ? wildabbr : gmtptr ? gmtptr->chars : utc)); + tmp->TM_ZONE = UNCONST(offset ? wildabbr + : gmtptr ? gmtptr->chars : utc); #endif /* defined TM_ZONE */ return result; } +#if !USE_TIMEX_T + /* * Re-entrant version of gmtime. */ @@ -1729,45 +1957,47 @@ gmtsub(ATTRIBUTE_MAYBE_UNUSED struct state const *sp, time_t const *timep, struct tm * gmtime_r(time_t const *restrict timep, struct tm *restrict tmp) { - _once(&gmt_once, gmtcheck); - return gmtsub(gmtptr, timep, 0, tmp); + gmtcheck(); + return gmtsub(gmtptr, timep, 0, tmp); } +#ifdef __FreeBSD__ static void gmtime_key_init(void) { - - gmtime_key_error = _pthread_key_create(&gmtime_key, free); + gmtime_key_error = _pthread_key_create(&gmtime_key, free); } - +#endif /* __FreeBSD__ */ struct tm * gmtime(const time_t *timep) { -#if !SUPPORT_C89 - static struct tm tm; -#endif - struct tm *p_tm = &tm; - - if (__isthreaded != 0) { - _pthread_once(&gmtime_once, gmtime_key_init); - if (gmtime_key_error != 0) { - errno = gmtime_key_error; - return (NULL); - } - if ((p_tm = _pthread_getspecific(gmtime_key)) == NULL) { - if ((p_tm = malloc(sizeof(*p_tm))) == NULL) { - return (NULL); - } - if (_pthread_setspecific(gmtime_key, p_tm) != 0) { - free(p_tm); - return (NULL); - } - } - } - return gmtime_r(timep, p_tm); +# if !SUPPORT_C89 + static struct tm tm; +# endif +#ifdef __FreeBSD__ + struct tm *p_tm = &tm; + + if (__isthreaded != 0) { + _pthread_once(&gmtime_once, gmtime_key_init); + if (gmtime_key_error != 0) { + errno = gmtime_key_error; + return (NULL); + } + if ((p_tm = _pthread_getspecific(gmtime_key)) == NULL) { + if ((p_tm = malloc(sizeof(*p_tm))) == NULL) { + return (NULL); + } + if (_pthread_setspecific(gmtime_key, p_tm) != 0) { + free(p_tm); + return (NULL); + } + } + } +#endif /* __FreeBSD__ */ + return gmtime_r(timep, p_tm); } -#if STD_INSPIRED +# if STD_INSPIRED /* This function is obsolescent and may disappear in future releases. Callers can instead use localtime_rz with a fixed-offset zone. */ @@ -1775,44 +2005,47 @@ gmtime(const time_t *timep) struct tm * offtime_r(time_t const *restrict timep, long offset, struct tm *restrict tmp) { - _once(&gmt_once, gmtcheck); - return gmtsub(gmtptr, timep, offset, tmp); + gmtcheck(); + return gmtsub(gmtptr, timep, offset, tmp); } +#ifdef __FreeBSD__ static void offtime_key_init(void) { - - offtime_key_error = _pthread_key_create(&offtime_key, free); + offtime_key_error = _pthread_key_create(&offtime_key, free); } - +#endif /* __FreeBSD__ */ struct tm * offtime(const time_t *timep, long offset) { -#if !SUPPORT_C89 - static struct tm tm; +# if !SUPPORT_C89 + static struct tm tm; +# endif +#ifdef __FreeBSD__ + struct tm *p_tm = &tm; + + if (__isthreaded != 0) { + _pthread_once(&offtime_once, offtime_key_init); + if (offtime_key_error != 0) { + errno = offtime_key_error; + return (NULL); + } + if ((p_tm = _pthread_getspecific(offtime_key)) == NULL) { + if ((p_tm = malloc(sizeof(*p_tm))) == NULL) { + return (NULL); + } + if (_pthread_setspecific(offtime_key, p_tm) != 0) { + free(p_tm); + return (NULL); + } + } + } #endif - struct tm *p_tm = &tm; - - if (__isthreaded != 0) { - _pthread_once(&offtime_once, offtime_key_init); - if (offtime_key_error != 0) { - errno = offtime_key_error; - return (NULL); - } - if ((p_tm = _pthread_getspecific(offtime_key)) == NULL) { - if ((p_tm = malloc(sizeof(*p_tm))) == NULL) { - return (NULL); - } - if (_pthread_setspecific(offtime_key, p_tm) != 0) { - free(p_tm); - return (NULL); - } - } - } - return offtime_r(timep, offset, p_tm); + return offtime_r(timep, offset, p_tm); } +# endif #endif /* @@ -1871,7 +2104,7 @@ timesub(const time_t *timep, int_fast32_t offset, dayoff = offset / SECSPERDAY - corr / SECSPERDAY + rem / SECSPERDAY - 3; rem %= SECSPERDAY; /* y = (EPOCH_YEAR - + floor((tdays + dayoff) / DAYSPERREPEAT) * YEARSPERREPEAT), + + floor((tdays + dayoff) / DAYSPERREPEAT) * YEARSPERREPEAT), sans overflow. But calculate against 1570 (EPOCH_YEAR - YEARSPERREPEAT) instead of against 1970 so that things work for localtime values before 1970 when time_t is unsigned. */ @@ -1988,17 +2221,17 @@ increment_overflow(int *ip, int j) } static bool -increment_overflow32(int_fast32_t *const lp, int const m) +increment_overflow_time_iinntt(time_t *tp, iinntt j) { #ifdef ckd_add - return ckd_add(lp, *lp, m); + return ckd_add(tp, *tp, j); #else - register int_fast32_t const l = *lp; - - if ((l >= 0) ? (m > INT_FAST32_MAX - l) : (m < INT_FAST32_MIN - l)) - return true; - *lp += m; - return false; + if (j < 0 + ? (TYPE_SIGNED(time_t) ? *tp < TIME_T_MIN - j : *tp <= -1 - j) + : TIME_T_MAX - j < *tp) + return true; + *tp += j; + return false; #endif } @@ -2022,30 +2255,6 @@ increment_overflow_time(time_t *tp, int_fast32_t j) #endif } -static bool -normalize_overflow(int *const tensptr, int *const unitsptr, const int base) -{ - register int tensdelta; - - tensdelta = (*unitsptr >= 0) ? - (*unitsptr / base) : - (-1 - (-1 - *unitsptr) / base); - *unitsptr -= tensdelta * base; - return increment_overflow(tensptr, tensdelta); -} - -static bool -normalize_overflow32(int_fast32_t *tensptr, int *unitsptr, int base) -{ - register int tensdelta; - - tensdelta = (*unitsptr >= 0) ? - (*unitsptr / base) : - (-1 - (-1 - *unitsptr) / base); - *unitsptr -= tensdelta * base; - return increment_overflow32(tensptr, tensdelta); -} - static int tmcomp(register const struct tm *const atmp, register const struct tm *const btmp) @@ -2090,11 +2299,9 @@ time2sub(struct tm *const tmp, { register int dir; register int i, j; - register int saved_seconds; - register int_fast32_t li; register time_t lo; register time_t hi; - int_fast32_t y; + iinntt y, mday, hour, min, saved_seconds; time_t newt; time_t t; struct tm yourtm, mytm; @@ -2102,36 +2309,57 @@ time2sub(struct tm *const tmp, *okayp = false; mktmcpy(&yourtm, tmp); + min = yourtm.tm_min; if (do_norm_secs) { - if (normalize_overflow(&yourtm.tm_min, &yourtm.tm_sec, - SECSPERMIN)) - return WRONG; + min += yourtm.tm_sec / SECSPERMIN; + yourtm.tm_sec %= SECSPERMIN; + if (yourtm.tm_sec < 0) { + yourtm.tm_sec += SECSPERMIN; + min--; + } } - if (normalize_overflow(&yourtm.tm_hour, &yourtm.tm_min, MINSPERHOUR)) - return WRONG; - if (normalize_overflow(&yourtm.tm_mday, &yourtm.tm_hour, HOURSPERDAY)) - return WRONG; + + hour = yourtm.tm_hour; + hour += min / MINSPERHOUR; + yourtm.tm_min = min % MINSPERHOUR; + if (yourtm.tm_min < 0) { + yourtm.tm_min += MINSPERHOUR; + hour--; + } + + mday = yourtm.tm_mday; + mday += hour / HOURSPERDAY; + yourtm.tm_hour = hour % HOURSPERDAY; + if (yourtm.tm_hour < 0) { + yourtm.tm_hour += HOURSPERDAY; + mday--; + } + y = yourtm.tm_year; - if (normalize_overflow32(&y, &yourtm.tm_mon, MONSPERYEAR)) - return WRONG; + y += yourtm.tm_mon / MONSPERYEAR; + yourtm.tm_mon %= MONSPERYEAR; + if (yourtm.tm_mon < 0) { + yourtm.tm_mon += MONSPERYEAR; + y--; + } + /* ** Turn y into an actual year number for now. ** It is converted back to an offset from TM_YEAR_BASE later. */ - if (increment_overflow32(&y, TM_YEAR_BASE)) - return WRONG; - while (yourtm.tm_mday <= 0) { - if (increment_overflow32(&y, -1)) - return WRONG; - li = y + (1 < yourtm.tm_mon); - yourtm.tm_mday += year_lengths[isleap(li)]; + y += TM_YEAR_BASE; + + while (mday <= 0) { + iinntt li = y - (yourtm.tm_mon <= 1); + mday += year_lengths[isleap(li)]; + y--; } - while (yourtm.tm_mday > DAYSPERLYEAR) { - li = y + (1 < yourtm.tm_mon); - yourtm.tm_mday -= year_lengths[isleap(li)]; - if (increment_overflow32(&y, 1)) - return WRONG; + while (DAYSPERLYEAR < mday) { + iinntt li = y + (1 < yourtm.tm_mon); + mday -= year_lengths[isleap(li)]; + y++; } + yourtm.tm_mday = mday; for ( ; ; ) { i = mon_lengths[isleap(y)][yourtm.tm_mon]; if (yourtm.tm_mday <= i) @@ -2139,16 +2367,14 @@ time2sub(struct tm *const tmp, yourtm.tm_mday -= i; if (++yourtm.tm_mon >= MONSPERYEAR) { yourtm.tm_mon = 0; - if (increment_overflow32(&y, 1)) - return WRONG; + y++; } } #ifdef ckd_add if (ckd_add(&yourtm.tm_year, y, -TM_YEAR_BASE)) return WRONG; #else - if (increment_overflow32(&y, -TM_YEAR_BASE)) - return WRONG; + y -= TM_YEAR_BASE; if (! (INT_MIN <= y && y <= INT_MAX)) return WRONG; yourtm.tm_year = y; @@ -2164,9 +2390,8 @@ time2sub(struct tm *const tmp, ** not in the same minute that a leap second was deleted from, ** which is a safer assumption than using 58 would be. */ - if (increment_overflow(&yourtm.tm_sec, 1 - SECSPERMIN)) - return WRONG; saved_seconds = yourtm.tm_sec; + saved_seconds -= SECSPERMIN - 1; yourtm.tm_sec = SECSPERMIN - 1; } else { saved_seconds = yourtm.tm_sec; @@ -2275,10 +2500,8 @@ time2sub(struct tm *const tmp, return WRONG; } label: - newt = t + saved_seconds; - if ((newt < t) != (saved_seconds < 0)) + if (increment_overflow_time_iinntt(&t, saved_seconds)) return WRONG; - t = newt; if (funcp(sp, &t, offset, tmp)) *okayp = true; return t; @@ -2323,7 +2546,6 @@ time1(struct tm *const tmp, errno = EINVAL; return WRONG; } - if (tmp->tm_isdst > 1) tmp->tm_isdst = 1; t = time2(tmp, funcp, sp, offset, &okay); @@ -2376,27 +2598,22 @@ time1(struct tm *const tmp, return WRONG; } +#if !defined TM_GMTOFF || !USE_TIMEX_T + static time_t mktime_tzname(struct state *sp, struct tm *tmp, bool setname) { if (sp) return time1(tmp, localsub, sp, setname); else { - _once(&gmt_once, gmtcheck); + gmtcheck(); return time1(tmp, gmtsub, gmtptr, 0); } } -#if NETBSD_INSPIRED - -time_t -mktime_z(struct state *restrict sp, struct tm *restrict tmp) -{ - return mktime_tzname(sp, tmp, false); -} - -#endif - +# if USE_TIMEX_T +static +# endif time_t mktime(struct tm *tmp) { @@ -2412,7 +2629,17 @@ mktime(struct tm *tmp) return t; } -#if STD_INSPIRED +#endif + +#if NETBSD_INSPIRED && !USE_TIMEX_T +time_t +mktime_z(struct state *restrict sp, struct tm *restrict tmp) +{ + return mktime_tzname(sp, tmp, false); +} +#endif + +#if STD_INSPIRED && !USE_TIMEX_T /* This function is obsolescent and may disappear in future releases. Callers can instead use mktime. */ time_t @@ -2424,12 +2651,14 @@ timelocal(struct tm *tmp) } #endif -#ifndef EXTERN_TIMEOFF -# ifndef timeoff -# define timeoff my_timeoff /* Don't collide with OpenBSD 7.4 <time.h>. */ +#if defined TM_GMTOFF || !USE_TIMEX_T + +# ifndef EXTERN_TIMEOFF +# ifndef timeoff +# define timeoff my_timeoff /* Don't collide with OpenBSD 7.4 <time.h>. */ +# endif +# define EXTERN_TIMEOFF static # endif -# define EXTERN_TIMEOFF static -#endif /* This function is obsolescent and may disappear in future releases. Callers can instead use mktime_z with a fixed-offset zone. */ @@ -2438,10 +2667,12 @@ timeoff(struct tm *tmp, long offset) { if (tmp) tmp->tm_isdst = 0; - _once(&gmt_once, gmtcheck); + gmtcheck(); return time1(tmp, gmtsub, gmtptr, offset); } +#endif +#if !USE_TIMEX_T time_t timegm(struct tm *tmp) { @@ -2454,6 +2685,7 @@ timegm(struct tm *tmp) *tmp = tmcpy; return t; } +#endif static int_fast32_t leapcorr(struct state const *sp, time_t t) @@ -2474,15 +2706,16 @@ leapcorr(struct state const *sp, time_t t) ** XXX--is the below the right way to conditionalize?? */ -#if STD_INSPIRED +#if !USE_TIMEX_T +# if STD_INSPIRED /* NETBSD_INSPIRED_EXTERN functions are exported to callers if NETBSD_INSPIRED is defined, and are private otherwise. */ -# if NETBSD_INSPIRED -# define NETBSD_INSPIRED_EXTERN -# else -# define NETBSD_INSPIRED_EXTERN static -# endif +# if NETBSD_INSPIRED +# define NETBSD_INSPIRED_EXTERN +# else +# define NETBSD_INSPIRED_EXTERN static +# endif /* ** IEEE Std 1003.1 (POSIX) says that 536457599 @@ -2508,7 +2741,7 @@ time2posix(time_t t) } #ifndef DETECT_TZ_CHANGES if (!lcl_is_set) -#endif +#endif /* DETECT_TZ_CHANGES */ tzset_unlocked(); if (lclptr) t = time2posix_z(lclptr, t); @@ -2555,7 +2788,7 @@ posix2time(time_t t) } #ifndef DETECT_TZ_CHANGES if (!lcl_is_set) -#endif +#endif /* DETECT_TZ_CHANGES */ tzset_unlocked(); if (lclptr) t = posix2time_z(lclptr, t); @@ -2563,17 +2796,13 @@ posix2time(time_t t) return t; } -#endif /* STD_INSPIRED */ +# endif /* STD_INSPIRED */ -#if TZ_TIME_T +# if TZ_TIME_T -# if !USG_COMPAT -# define daylight 0 -# define timezone 0 -# endif -# if !ALTZONE -# define altzone 0 -# endif +# if !USG_COMPAT +# define timezone 0 +# endif /* Convert from the underlying system's time_t to the ersatz time_tz, which is called 'time_t' in this file. Typically, this merely @@ -2591,9 +2820,9 @@ time(time_t *p) { time_t r = sys_time(0); if (r != (time_t) -1) { - int_fast32_t offset = EPOCH_LOCAL ? (daylight ? timezone : altzone) : 0; - if (increment_overflow32(&offset, -EPOCH_OFFSET) - || increment_overflow_time(&r, offset)) { + iinntt offset = EPOCH_LOCAL ? timezone : 0; + if (offset < IINNTT_MIN + EPOCH_OFFSET + || increment_overflow_time_iinntt(&r, offset - EPOCH_OFFSET)) { errno = EOVERFLOW; r = -1; } @@ -2603,4 +2832,5 @@ time(time_t *p) return r; } +# endif #endif diff --git a/contrib/tzcode/newctime.3 b/contrib/tzcode/newctime.3 index d19fd25b7926..9d09e5a55bd9 100644 --- a/contrib/tzcode/newctime.3 +++ b/contrib/tzcode/newctime.3 @@ -5,43 +5,34 @@ asctime, ctime, difftime, gmtime, localtime, mktime \- convert date and time .SH SYNOPSIS .nf -.ie \n(.g .ds - \f(CR-\fP -.el .ds - \- .B #include <time.h> .PP -.B [[deprecated]] char *ctime(time_t const *clock); -.PP -/* Only in POSIX.1-2017 and earlier. */ -.B char *ctime_r(time_t const *clock, char *buf); -.PP -.B double difftime(time_t time1, time_t time0); -.PP -.B [[deprecated]] char *asctime(struct tm const *tm); -.PP -/* Only in POSIX.1-2017 and earlier. */ -.B "char *asctime_r(struct tm const *restrict tm," -.B " char *restrict result);" -.PP .B struct tm *localtime(time_t const *clock); -.PP .B "struct tm *localtime_r(time_t const *restrict clock," .B " struct tm *restrict result);" -.PP .B "struct tm *localtime_rz(timezone_t restrict zone," .B " time_t const *restrict clock," .B " struct tm *restrict result);" .PP .B struct tm *gmtime(time_t const *clock); -.PP .B "struct tm *gmtime_r(time_t const *restrict clock," .B " struct tm *restrict result);" .PP .B time_t mktime(struct tm *tm); -.PP .B "time_t mktime_z(timezone_t restrict zone," .B " struct tm *restrict tm);" .PP -.B cc ... \*-ltz +.B double difftime(time_t time1, time_t time0); +.PP +.B [[deprecated]] char *asctime(struct tm const *tm); +.B [[deprecated]] char *ctime(time_t const *clock); +.PP +/* Only in POSIX.1-2017 and earlier. */ +.B char *ctime_r(time_t const *clock, char *buf); +.B "char *asctime_r(struct tm const *restrict tm," +.B " char *restrict result);" +.PP +.B cc ... \-ltz .fi .SH DESCRIPTION .ie '\(en'' .ds en \- @@ -54,82 +45,37 @@ asctime, ctime, difftime, gmtime, localtime, mktime \- convert date and time \\$3\*(lq\\$1\*(rq\\$2 .. The -.B ctime -function -converts a long integer, pointed to by -.IR clock , -and returns a pointer to a -string of the form -.br -.ce -.eo -Thu Nov 24 18:22:48 1986\n\0 -.br -.ec -Years requiring fewer than four characters are padded with leading zeroes. -For years longer than four characters, the string is of the form -.br -.ce -.eo -Thu Nov 24 18:22:48 81986\n\0 -.ec -.br -with five spaces before the year. -These unusual formats are designed to make it less likely that older -software that expects exactly 26 bytes of output will mistakenly output -misleading values for out-of-range years. -.PP -The -.BI * clock -timestamp represents the time in seconds since 1970-01-01 00:00:00 -Coordinated Universal Time (UTC). -The POSIX standard says that timestamps must be nonnegative -and must ignore leap seconds. -Many implementations extend POSIX by allowing negative timestamps, -and can therefore represent timestamps that predate the -introduction of UTC and are some other flavor of Universal Time (UT). -Some implementations support leap seconds, in contradiction to POSIX. -.PP -The -.B ctime -function is deprecated starting in C23. -Callers can use -.B localtime_r -and -.B strftime -instead. -.PP -The .B localtime and .B gmtime functions +convert an integer, pointed to by +.IR clock , +and return pointers to .q "tm" structures, described below. +If the integer is out of range for conversion, +these functions return a null pointer. The .B localtime function corrects for the time zone and any time zone adjustments (such as Daylight Saving Time in the United States). -.PP The .B gmtime -function -converts to Coordinated Universal Time. +function converts to Coordinated Universal Time. .PP The -.B asctime -function -converts a time value contained in a -.q "tm" -structure to a string, -as shown in the above example, -and returns a pointer to the string. -This function is deprecated starting in C23. -Callers can use -.B strftime -instead. +.BI * clock +timestamp represents the time in seconds since 1970-01-01 00:00:00 +Coordinated Universal Time (UTC). +The POSIX standard says that timestamps must be nonnegative +and must ignore leap seconds. +Many implementations extend POSIX by allowing negative timestamps, +and can therefore represent timestamps that predate the +introduction of UTC and are some other flavor of Universal Time (UT). +Some implementations support leap seconds, in contradiction to POSIX. .PP The .B mktime @@ -204,6 +150,52 @@ returns the difference between two calendar times, expressed in seconds. .PP The +.B asctime +function +converts a time value contained in a +.q "tm" +structure to a pointer to a +string of the form +.br +.ce +.eo +Thu Nov 24 18:22:48 1986\n\0 +.br +.ec +Years requiring fewer than four characters are padded with leading zeroes. +For years longer than four characters, the string is of the form +.br +.ce +.eo +Thu Nov 24 18:22:48 81986\n\0 +.ec +.br +with five spaces before the year. +This unusual format is designed to make it less likely that older +software that expects exactly 26 bytes of output will mistakenly output +misleading values for out-of-range years. +This function is deprecated starting in C23. +Callers can use +.B strftime +instead. +.PP +The +.B ctime +function is equivalent to calliing +.B localtime +and then calling +.B asctime +on the result. +Like +.BR asctime , +this function is deprecated starting in C23. +Callers can use +.B localtime +and +.B strftime +instead. +.PP +The .BR ctime_r , .BR localtime_r , .BR gmtime_r , diff --git a/contrib/tzcode/newstrftime.3 b/contrib/tzcode/newstrftime.3 index a9997a092d0a..e9a382240ed2 100644 --- a/contrib/tzcode/newstrftime.3 +++ b/contrib/tzcode/newstrftime.3 @@ -40,8 +40,6 @@ strftime \- format date and time .SH SYNOPSIS .nf -.ie \n(.g .ds - \f(CR-\fP -.el .ds - \- .B #include <time.h> .PP .B "size_t strftime(char *restrict buf, size_t maxsize," @@ -93,7 +91,7 @@ If a bracketed member name is followed by .B strftime can use the named member even though POSIX.1-2024 does not list it; if the name is followed by -.q \*- , +.q \- , .B strftime ignores the member even though POSIX.1-2024 lists it which means portable code should set it. @@ -139,11 +137,14 @@ is replaced by the locale's appropriate date and time representation. .IR tm_sec , .IR tm_gmtoff , .IR tm_zone , -.IR tm_isdst \*-]. +.IR tm_isdst \-]. .TP %D is equivalent to .c %m/%d/%y . +Although used in the United States for current dates, +this format is ambiguous elsewhere +and for dates that might involve other centuries. .RI [ tm_year , .IR tm_mon , .IR tm_mday ] @@ -167,6 +168,8 @@ is equivalent to .TP %G is replaced by the ISO 8601 year with century as a decimal number. +This is the year that includes the greater part of the week. +(Monday as the first day of a week). See also the .c %V conversion specification. @@ -176,11 +179,7 @@ conversion specification. .TP %g is replaced by the ISO 8601 year without century as a decimal number [00,99]. -This is the year that includes the greater part of the week. -(Monday as the first day of a week). -See also the -.c %V -conversion specification. +Since it omits the century, it is ambiguous for dates. .RI [ tm_year , .IR tm_yday , .IR tm_wday ] @@ -249,9 +248,22 @@ of leap seconds. is replaced by the number of seconds since the Epoch (see .BR ctime (3)). Although %s is reliable in this implementation, -it can have glitches on other platforms (notably platforms lacking -.IR tm_gmtoff ), -so portable code should format a +it can have glitches on other platforms +(notably obsolescent platforms lacking +.I tm_gmtoff +or where +.B time_t +is no wider than int), and POSIX allows +.B strftime +to set +.B errno +to +.B EINVAL +or +.B EOVERFLOW +and return 0 if the number of seconds would be negative or out of range for +.BR time_t . +Portable code should therefore format a .B time_t value directly via something like .B sprintf @@ -267,7 +279,7 @@ with "%s". .IR tm_min , .IR tm_sec , .IR tm_gmtoff +, -.IR tm_isdst \*-]. +.IR tm_isdst \-]. .TP %T is replaced by the time in the format @@ -284,7 +296,7 @@ is replaced by the week number of the year (Sunday as the first day of the week) as a decimal number [00,53]. .RI [ tm_wday , .IR tm_yday , -.IR tm_year \*-] +.IR tm_year \-] .TP %u is replaced by the weekday (Monday as the first day of the week) @@ -318,31 +330,33 @@ as a decimal number [0,6]. .TP %X is replaced by the locale's appropriate time representation. -.RI [ tm_year \*-, -.IR tm_yday \*-, -.IR tm_mon \*-, -.IR tm_mday \*-, -.IR tm_wday \*-, +.RI [ tm_year \-, +.IR tm_yday \-, +.IR tm_mon \-, +.IR tm_mday \-, +.IR tm_wday \-, .IR tm_hour , .IR tm_min , .IR tm_sec , .IR tm_gmtoff , .IR tm_zone , -.IR tm_isdst \*-]. +.IR tm_isdst \-]. .TP %x is replaced by the locale's appropriate date representation. +This format can be ambiguous for dates, e.g., +it can generate "01/02/03" in the C locale. .RI [ tm_year , .IR tm_yday , .IR tm_mon , .IR tm_mday , .IR tm_wday , -.IR tm_hour \*-, -.IR tm_min \*-, -.IR tm_sec \*-, -.IR tm_gmtoff \*-, -.IR tm_zone \*-, -.IR tm_isdst \*-]. +.IR tm_hour \-, +.IR tm_min \-, +.IR tm_sec \-, +.IR tm_gmtoff \-, +.IR tm_zone \-, +.IR tm_isdst \-]. .TP %Y is replaced by the year with century as a decimal number. @@ -350,28 +364,29 @@ is replaced by the year with century as a decimal number. .TP %y is replaced by the year without century as a decimal number [00,99]. +Since it omits the century, it is ambiguous for dates. .RI [ tm_year ] .TP %Z is replaced by the time zone abbreviation, or by the empty string if this is not determinable. .RI [ tm_zone , -.IR tm_isdst \*-] +.IR tm_isdst \-] .TP %z is replaced by the offset from the Prime Meridian -in the format +HHMM or \*-HHMM (ISO 8601) as appropriate, +in the format +HHMM or \-HHMM (ISO 8601) as appropriate, with positive values representing locations east of Greenwich, or by the empty string if this is not determinable. -The numeric time zone abbreviation \*-0000 is used when the time is +The numeric time zone abbreviation \-0000 is used when the time is Universal Time but local time is indeterminate; by convention this is used for locations while uninhabited, and corresponds to a zero offset when the time zone abbreviation begins with -.q "\*-" . +.q "\-" . .RI [ tm_gmtoff , .IR tm_zone +, -.IR tm_isdst \*-] +.IR tm_isdst \-] .TP %% is replaced by a single %. @@ -418,15 +433,6 @@ This function fails if: The total number of resulting bytes, including the terminating NUL character, is more than .IR maxsize . -.PP -This function may fail if: -.TP -[EOVERFLOW] -The format includes an -.c %s -conversion and the number of seconds since the Epoch cannot be represented -in a -.c time_t . .SH SEE ALSO .BR date (1), .BR getenv (3), diff --git a/contrib/tzcode/newtzset.3 b/contrib/tzcode/newtzset.3 index 661fb25be098..db6bfa7fa64c 100644 --- a/contrib/tzcode/newtzset.3 +++ b/contrib/tzcode/newtzset.3 @@ -5,8 +5,6 @@ tzset \- initialize time conversion information .SH SYNOPSIS .nf -.ie \n(.g .ds - \f(CR-\fP -.el .ds - \- .B #include <time.h> .PP .BI "timezone_t tzalloc(char const *" TZ ); @@ -23,7 +21,7 @@ tzset \- initialize time conversion information .br .B extern int daylight; .PP -.B cc ... \*-ltz +.B cc ... \-ltz .fi .SH DESCRIPTION .ie '\(en'' .ds en \- @@ -110,7 +108,7 @@ except a leading colon digits, comma .RB ( , ), ASCII minus -.RB ( \*- ), +.RB ( \- ), ASCII plus .RB ( + ), and NUL bytes are allowed. @@ -150,7 +148,7 @@ daylight saving time is assumed to be one hour ahead of standard time. One or more digits may be used; the value is always interpreted as a decimal number. The hour must be between zero and 24, and the minutes (and seconds) \*(en if present \*(en between zero and 59. If preceded by a -.q "\*-" , +.q "\-" , the time zone shall be east of the Prime Meridian; otherwise it shall be west (which may be indicated by an optional preceding .q "+" . @@ -239,7 +237,7 @@ values that directly specify the timezone. stands for US Eastern Standard Time (EST), 5 hours behind UT, without daylight saving. .TP -.B <+12>\*-12<+13>,M11.1.0,M1.2.1/147 +.B <+12>\-12<+13>,M11.1.0,M1.2.1/147 stands for Fiji time, 12 hours ahead of UT, springing forward on November's first Sunday at 02:00, and falling back on January's second Monday at 147:00 (i.e., 03:00 on the @@ -249,34 +247,34 @@ and daylight saving time are and .q "+13". .TP -.B IST\*-2IDT,M3.4.4/26,M10.5.0 +.B IST\-2IDT,M3.4.4/26,M10.5.0 stands for Israel Standard Time (IST) and Israel Daylight Time (IDT), 2 hours ahead of UT, springing forward on March's fourth Thursday at 26:00 (i.e., 02:00 on the first Friday on or after March 23), and falling back on October's last Sunday at 02:00. .TP -.B <\*-04>4<\*-03>,J1/0,J365/25 +.B <\-04>4<\-03>,J1/0,J365/25 stands for permanent daylight saving time, 3 hours behind UT with abbreviation -.q "\*-03". +.q "\-03". There is a dummy fall-back transition on December 31 at 25:00 daylight saving time (i.e., 24:00 standard time, equivalent to January 1 at 00:00 standard time), and a simultaneous spring-forward transition on January 1 at 00:00 standard time, so daylight saving time is in effect all year and the initial -.B <\*-04> +.B <\-04> is a placeholder. .TP -.B <\*-03>3<\*-02>,M3.5.0/\*-2,M10.5.0/\*-1 +.B <\-03>3<\-02>,M3.5.0/\-2,M10.5.0/\-1 stands for time in western Greenland, 3 hours behind UT, where clocks follow the EU rules of springing forward on March's last Sunday at 01:00 UT (\-02:00 local time, i.e., 22:00 the previous day) and falling back on October's last Sunday at 01:00 UT (\-01:00 local time, i.e., 23:00 the previous day). The abbreviations for standard and daylight saving time are -.q "\*-03" +.q "\-03" and -.q "\*-02". +.q "\-02". .PP If .I TZ diff --git a/contrib/tzcode/private.h b/contrib/tzcode/private.h index 9c5edff252fd..532d9ddc81c8 100644 --- a/contrib/tzcode/private.h +++ b/contrib/tzcode/private.h @@ -37,6 +37,38 @@ # define SUPPORT_C89 1 #endif + +/* The following feature-test macros should be defined before + any #include of a system header. */ + +/* Enable tm_gmtoff, tm_zone, and environ on GNUish systems. */ +#define _GNU_SOURCE 1 +/* Fix asctime_r on Solaris 11. */ +#define _POSIX_PTHREAD_SEMANTICS 1 +/* Enable strtoimax on pre-C99 Solaris 11. */ +#define __EXTENSIONS__ 1 +/* Cause MS-Windows headers to define POSIX names. */ +#define _CRT_DECLARE_NONSTDC_NAMES 1 +/* Prevent MS-Windows headers from defining min and max. */ +#define NOMINMAX 1 + +/* On GNUish systems where time_t might be 32 or 64 bits, use 64. + On these platforms _FILE_OFFSET_BITS must also be 64; otherwise + setting _TIME_BITS to 64 does not work. The code does not + otherwise rely on _FILE_OFFSET_BITS being 64, since it does not + use off_t or functions like 'stat' that depend on off_t. */ +#ifndef _TIME_BITS +# ifndef _FILE_OFFSET_BITS +# define _FILE_OFFSET_BITS 64 +# endif +# if _FILE_OFFSET_BITS == 64 +# define _TIME_BITS 64 +# endif +#endif + +/* End of feature-test macro definitions. */ + + #ifndef __STDC_VERSION__ # define __STDC_VERSION__ 0 #endif @@ -51,6 +83,7 @@ #endif #if __STDC_VERSION__ < 202311 +# undef static_assert # define static_assert(cond) extern int static_assert_check[(cond) ? 1 : -1] #endif @@ -87,11 +120,11 @@ #if !defined HAVE_GETTEXT && defined __has_include # if __has_include(<libintl.h>) -# define HAVE_GETTEXT true +# define HAVE_GETTEXT 1 # endif #endif #ifndef HAVE_GETTEXT -# define HAVE_GETTEXT false +# define HAVE_GETTEXT 0 #endif #ifndef HAVE_INCOMPATIBLE_CTIME_R @@ -124,20 +157,20 @@ #if !defined HAVE_SYS_STAT_H && defined __has_include # if !__has_include(<sys/stat.h>) -# define HAVE_SYS_STAT_H false +# define HAVE_SYS_STAT_H 0 # endif #endif #ifndef HAVE_SYS_STAT_H -# define HAVE_SYS_STAT_H true +# define HAVE_SYS_STAT_H 1 #endif #if !defined HAVE_UNISTD_H && defined __has_include # if !__has_include(<unistd.h>) -# define HAVE_UNISTD_H false +# define HAVE_UNISTD_H 0 # endif #endif #ifndef HAVE_UNISTD_H -# define HAVE_UNISTD_H true +# define HAVE_UNISTD_H 1 #endif #ifndef NETBSD_INSPIRED @@ -149,25 +182,6 @@ # define ctime_r _incompatible_ctime_r #endif /* HAVE_INCOMPATIBLE_CTIME_R */ -/* Enable tm_gmtoff, tm_zone, and environ on GNUish systems. */ -#define _GNU_SOURCE 1 -/* Fix asctime_r on Solaris 11. */ -#define _POSIX_PTHREAD_SEMANTICS 1 -/* Enable strtoimax on pre-C99 Solaris 11. */ -#define __EXTENSIONS__ 1 - -/* On GNUish systems where time_t might be 32 or 64 bits, use 64. - On these platforms _FILE_OFFSET_BITS must also be 64; otherwise - setting _TIME_BITS to 64 does not work. The code does not - otherwise rely on _FILE_OFFSET_BITS being 64, since it does not - use off_t or functions like 'stat' that depend on off_t. */ -#ifndef _FILE_OFFSET_BITS -# define _FILE_OFFSET_BITS 64 -#endif -#if !defined _TIME_BITS && _FILE_OFFSET_BITS == 64 -# define _TIME_BITS 64 -#endif - /* ** Nested includes */ @@ -260,6 +274,10 @@ # endif #endif +#ifndef HAVE_SNPRINTF +# define HAVE_SNPRINTF (!PORT_TO_C89 || 199901 <= __STDC_VERSION__) +#endif + #ifndef HAVE_STRFTIME_L # if _POSIX_VERSION < 200809 # define HAVE_STRFTIME_L 0 @@ -305,7 +323,7 @@ ** stdint.h, even with pre-C99 compilers. */ #if !defined HAVE_STDINT_H && defined __has_include -# define HAVE_STDINT_H true /* C23 __has_include implies C99 stdint.h. */ +# define HAVE_STDINT_H 1 /* C23 __has_include implies C99 stdint.h. */ #endif #ifndef HAVE_STDINT_H # define HAVE_STDINT_H \ @@ -375,11 +393,15 @@ typedef int int_fast32_t; # endif #endif +#ifndef INT_LEAST32_MAX +typedef int_fast32_t int_least32_t; +#endif + #ifndef INTMAX_MAX # ifdef LLONG_MAX typedef long long intmax_t; # ifndef HAVE_STRTOLL -# define HAVE_STRTOLL true +# define HAVE_STRTOLL 1 # endif # if HAVE_STRTOLL # define strtoimax strtoll @@ -459,7 +481,7 @@ typedef unsigned long uintmax_t; hosts, unless compiled with -DHAVE_STDCKDINT_H=0 or with pre-C23 EDG. */ #if !defined HAVE_STDCKDINT_H && defined __has_include # if __has_include(<stdckdint.h>) -# define HAVE_STDCKDINT_H true +# define HAVE_STDCKDINT_H 1 # endif #endif #ifdef HAVE_STDCKDINT_H @@ -554,13 +576,26 @@ typedef unsigned long uintmax_t; # define ATTRIBUTE_REPRODUCIBLE /* empty */ #endif +#if HAVE___HAS_C_ATTRIBUTE +# if __has_c_attribute(unsequenced) +# define ATTRIBUTE_UNSEQUENCED [[unsequenced]] +# endif +#endif +#ifndef ATTRIBUTE_UNSEQUENCED +# define ATTRIBUTE_UNSEQUENCED /* empty */ +#endif + /* GCC attributes that are useful in tzcode. + __attribute__((const)) is stricter than [[unsequenced]], + so the latter is an adequate substitute in non-GCC C23 platforms. __attribute__((pure)) is stricter than [[reproducible]], so the latter is an adequate substitute in non-GCC C23 platforms. */ #if __GNUC__ < 3 +# define ATTRIBUTE_CONST ATTRIBUTE_UNSEQUENCED # define ATTRIBUTE_FORMAT(spec) /* empty */ # define ATTRIBUTE_PURE ATTRIBUTE_REPRODUCIBLE #else +# define ATTRIBUTE_CONST __attribute__((const)) # define ATTRIBUTE_FORMAT(spec) __attribute__((format spec)) # define ATTRIBUTE_PURE __attribute__((pure)) #endif @@ -593,6 +628,12 @@ typedef unsigned long uintmax_t; # define RESERVE_STD_EXT_IDS 0 #endif +#ifdef time_tz +# define defined_time_tz true +#else +# define defined_time_tz false +#endif + /* If standard C identifiers with external linkage (e.g., localtime) are reserved and are not already being renamed anyway, rename them as if compiling with '-Dtime_tz=time_t'. */ @@ -608,9 +649,9 @@ typedef unsigned long uintmax_t; ** typical platforms. */ #if defined time_tz || EPOCH_LOCAL || EPOCH_OFFSET != 0 -# define TZ_TIME_T 1 +# define TZ_TIME_T true #else -# define TZ_TIME_T 0 +# define TZ_TIME_T false #endif #if defined LOCALTIME_IMPLEMENTATION && TZ_TIME_T @@ -707,7 +748,7 @@ DEPRECATED_IN_C23 char *ctime(time_t const *); char *asctime_r(struct tm const *restrict, char *restrict); char *ctime_r(time_t const *, char *); #endif -double difftime(time_t, time_t); +ATTRIBUTE_CONST double difftime(time_t, time_t); size_t strftime(char *restrict, size_t, char const *restrict, struct tm const *restrict); # if HAVE_STRFTIME_L @@ -729,9 +770,9 @@ void tzset(void); || defined __GLIBC__ || defined __tm_zone /* musl */ \ || defined __FreeBSD__ || defined __NetBSD__ || defined __OpenBSD__ \ || (defined __APPLE__ && defined __MACH__)) -# define HAVE_DECL_TIMEGM true +# define HAVE_DECL_TIMEGM 1 # else -# define HAVE_DECL_TIMEGM false +# define HAVE_DECL_TIMEGM 0 # endif #endif #if !HAVE_DECL_TIMEGM && !defined timegm @@ -771,7 +812,11 @@ extern long altzone; */ #ifndef STD_INSPIRED -# define STD_INSPIRED 0 +# ifdef __NetBSD__ +# define STD_INSPIRED 1 +# else +# define STD_INSPIRED 0 +# endif #endif #if STD_INSPIRED # if TZ_TIME_T || !defined offtime @@ -880,7 +925,7 @@ ATTRIBUTE_PURE time_t time2posix_z(timezone_t, time_t); default: TIME_T_MAX_NO_PADDING) \ : (time_t) -1) enum { SIGNED_PADDING_CHECK_NEEDED - = _Generic((time_t) 0, + = _Generic((time_t) 0, signed char: false, short: false, int: false, long: false, long long: false, default: true) }; @@ -927,8 +972,8 @@ static_assert(! TYPE_SIGNED(time_t) || ! SIGNED_PADDING_CHECK_NEEDED # define UNINIT_TRAP 0 #endif -/* localtime.c sometimes needs access to timeoff if it is not already public. - tz_private_timeoff should be used only by localtime.c. */ +/* strftime.c sometimes needs access to timeoff if it is not already public. + tz_private_timeoff should be used only by localtime.c and strftime.c. */ #if (!defined EXTERN_TIMEOFF \ && defined TM_GMTOFF && (200809 < _POSIX_VERSION || ! UNINIT_TRAP)) # ifndef timeoff diff --git a/contrib/tzcode/strftime.c b/contrib/tzcode/strftime.c index 755d341fa6d9..487a5234cbc5 100644 --- a/contrib/tzcode/strftime.c +++ b/contrib/tzcode/strftime.c @@ -39,8 +39,63 @@ #include <locale.h> #include <stdio.h> +/* If true, the value returned by an idealized unlimited-range mktime + always fits into an integer type with bounds MIN and MAX. + If false, the value might not fit. + This macro is usable in #if if its arguments are. + Add or subtract 2**31 - 1 for the maximum UT offset allowed in a TZif file, + divide by the maximum number of non-leap seconds in a year, + divide again by two just to be safe, + and account for the tm_year origin (1900) and time_t origin (1970). */ +#define MKTIME_FITS_IN(min, max) \ + ((min) < 0 \ + && ((min) + 0x7fffffff) / 366 / 24 / 60 / 60 / 2 + 1970 - 1900 < INT_MIN \ + && INT_MAX < ((max) - 0x7fffffff) / 366 / 24 / 60 / 60 / 2 + 1970 - 1900) + +/* MKTIME_MIGHT_OVERFLOW is true if mktime can fail due to time_t overflow + or if it is not known whether mktime can fail, + and is false if mktime definitely cannot fail. + This macro is usable in #if, and so does not use TIME_T_MAX or sizeof. + If the builder has not configured this macro, guess based on what + known platforms do. When in doubt, guess true. */ +#ifndef MKTIME_MIGHT_OVERFLOW +# if defined __FreeBSD__ || defined __NetBSD__ || defined __OpenBSD__ +# include <sys/param.h> +# endif +# if ((/* The following heuristics assume native time_t. */ \ + defined_time_tz) \ + || ((/* Traditional time_t is 'long', so if 'long' is not wide enough \ + assume overflow unless we're on a known-safe host. */ \ + !MKTIME_FITS_IN(LONG_MIN, LONG_MAX)) \ + && (/* GNU C Library 2.29 (2019-02-01) and later has 64-bit time_t \ + if __TIMESIZE is 64. */ \ + !defined __TIMESIZE || __TIMESIZE < 64) \ + && (/* FreeBSD 12 r320347 (__FreeBSD_version 1200036; 2017-06-26), \ + and later has 64-bit time_t on all platforms but i386 which \ + is currently scheduled for end-of-life on 2028-11-30. */ \ + !defined __FreeBSD_version || __FreeBSD_version < 1200036 \ + || defined __i386) \ + && (/* NetBSD 6.0 (2012-10-17) and later has 64-bit time_t. */ \ + !defined __NetBSD_Version__ || __NetBSD_Version__ < 600000000) \ + && (/* OpenBSD 5.5 (2014-05-01) and later has 64-bit time_t. */ \ + !defined OpenBSD || OpenBSD < 201405))) +# define MKTIME_MIGHT_OVERFLOW 1 +# else +# define MKTIME_MIGHT_OVERFLOW 0 +# endif +#endif +/* Check that MKTIME_MIGHT_OVERFLOW is consistent with time_t's range. */ +static_assert(MKTIME_MIGHT_OVERFLOW + || MKTIME_FITS_IN(TIME_T_MIN, TIME_T_MAX)); + +#if MKTIME_MIGHT_OVERFLOW +/* Do this after system includes as it redefines time_t, mktime, timeoff. */ +# define USE_TIMEX_T true +# include "localtime.c" +#endif + #ifndef DEPRECATE_TWO_DIGIT_YEARS -# define DEPRECATE_TWO_DIGIT_YEARS false +# define DEPRECATE_TWO_DIGIT_YEARS 0 #endif struct lc_time_T { @@ -135,10 +190,6 @@ strftime(char *restrict s, size_t maxsize, char const *restrict format, tzset(); p = _fmt(format, t, s, s + maxsize, &warn); - if (!p) { - errno = EOVERFLOW; - return 0; - } if (DEPRECATE_TWO_DIGIT_YEARS && warn != IN_NONE && getenv(YEAR_2000_NAME)) { fprintf(stderr, "\n"); @@ -170,7 +221,12 @@ _fmt(const char *format, const struct tm *t, char *pt, if (*format == '%') { label: switch (*++format) { - case '\0': + default: + /* Output unknown conversion specifiers as-is, + to aid debugging. This includes '%' at + format end. This conforms to C23 section + 7.29.3.5 paragraph 6, which says behavior + is undefined here. */ --format; break; case 'A': @@ -327,16 +383,17 @@ label: tm.tm_mday = t->tm_mday; tm.tm_mon = t->tm_mon; tm.tm_year = t->tm_year; + + /* Get the time_t value for TM. + Native time_t, or its redefinition + by localtime.c above, is wide enough + so that this cannot overflow. */ #ifdef TM_GMTOFF mkt = timeoff(&tm, t->TM_GMTOFF); #else tm.tm_isdst = t->tm_isdst; mkt = mktime(&tm); #endif - /* If mktime fails, %s expands to the - value of (time_t) -1 as a failure - marker; this is better in practice - than strftime failing. */ if (TYPE_SIGNED(time_t)) { intmax_t n = mkt; sprintf(buf, "%"PRIdMAX, n); @@ -590,12 +647,6 @@ label: warnp); continue; case '%': - /* - ** X311J/88-090 (4.12.3.5): if conversion char is - ** undefined, behavior is undefined. Print out the - ** character itself as printf(3) also does. - */ - default: break; } } diff --git a/contrib/tzcode/theory.html b/contrib/tzcode/theory.html index d3573ede0dfb..352a3d87078f 100644 --- a/contrib/tzcode/theory.html +++ b/contrib/tzcode/theory.html @@ -123,8 +123,9 @@ If geolocation information is available, a selection interface can locate the user on a timezone map or prioritize names that are geographically close. For an example selection interface, see the <code>tzselect</code> program in the <code><abbr>tz</abbr></code> code. -The <a href="https://cldr.unicode.org">Unicode Common Locale Data -Repository</a> contains data that may be useful for other selection +Unicode's <a href="https://cldr.unicode.org">Common Locale Data +Repository (<abbr>CLDR</abbr>)</a> +contains data that may be useful for other selection interfaces; it maps timezone names like <code>Europe/Prague</code> to locale-dependent strings like "Prague", "Praha", "Прага", and "å¸ƒæ‹‰æ ¼". </p> @@ -200,6 +201,8 @@ in decreasing order of importance: <li> A name must not be empty, or contain '<code>//</code>', or start or end with '<code>/</code>'. + Also, a name must not be '<code>Etc/Unknown</code>', as + <abbr>CLDR</abbr> uses that string for an unknown or invalid timezone. </li> <li> Do not use names that differ only in case. @@ -220,10 +223,18 @@ in decreasing order of importance: do not need locations, since local time is not defined there. </li> <li> - If all the clocks in a timezone have agreed since 1970, - do not bother to include more than one timezone - even if some of the clocks disagreed before 1970. + If all clocks in a region have agreed since 1970, + give them just one name even if some of the clocks disagreed before 1970, + or reside in different countries or in notable or faraway locations. Otherwise these tables would become annoyingly large. + For example, do not create a name <code>Indian/Crozet</code> + as a near-duplicate or alias of <code>Asia/Dubai</code> + merely because they are different countries or territories, + or their clocks disagreed before 1970, or the + <a href="https://en.wikipedia.org/wiki/Crozet_Islands">Crozet Islands</a> + are notable in their own right, + or the Crozet Islands are not adjacent to other locations + that use <code>Asia/Dubai</code>. </li> <li> If boundaries between regions are fluid, such as during a war or @@ -579,10 +590,10 @@ in decreasing order of importance: locations while uninhabited. The leading '<code>-</code>' is a flag that the <abbr>UT</abbr> offset is in some sense undefined; this notation is derived - from <a href="https://datatracker.ietf.org/doc/html/rfc3339">Internet + from <a href="https://www.rfc-editor.org/rfc/rfc3339">Internet <abbr title="Request For Comments">RFC</abbr> 3339</a>. (The abbreviation 'Z' that - <a href="https://datatracker.ietf.org/doc/html/rfc9557">Internet + <a href="https://www.rfc-editor.org/rfc/rfc9557">Internet <abbr>RFC</abbr> 9557</a> uses for this concept would violate the POSIX requirement of at least three characters in an abbreviation.) @@ -1115,8 +1126,8 @@ However POSIX.1-2024, like earlier POSIX editions, has some limitations: the name of a file from which time-related information is read. The file's format is <dfn><abbr>TZif</abbr></dfn>, a timezone information format that contains binary data; see - <a href="https://datatracker.ietf.org/doc/html/8536">Internet - <abbr>RFC</abbr> 8536</a>. + <a href="https://www.rfc-editor.org/rfc/9636">Internet + <abbr>RFC</abbr> 9636</a>. The daylight saving time rules to be used for a particular timezone are encoded in the <abbr>TZif</abbr> file; the format of the file allows <abbr>US</abbr>, @@ -1201,12 +1212,15 @@ The vestigial <abbr>API</abbr>s are: The <code>tm_isdst</code> member is almost never needed and most of its uses should be discouraged in favor of the abovementioned <abbr>API</abbr>s. + It was intended as an index into the <code>tzname</code> variable, + but as mentioned previously that usage is obsolete. Although it can still be used in arguments to <code>mktime</code> to disambiguate timestamps near a <abbr>DST</abbr> transition when the clock jumps back on platforms lacking <code>tm_gmtoff</code>, this - disambiguation does not work when standard time itself jumps back, - which can occur when a location changes to a time zone with a + disambiguation works only for proleptic <code>TZ</code> strings; + it does not work in general for geographical timezones, + such as when a location changes to a time zone with a lesser <abbr>UT</abbr> offset. </li> </ul> @@ -1223,8 +1237,8 @@ The vestigial <abbr>API</abbr>s are: Programs that in the past used the <code>timezone</code> function may now examine <code>localtime(&clock)->tm_zone</code> (if <code>TM_ZONE</code> is defined) or - <code>tzname[localtime(&clock)->tm_isdst]</code> - (if <code>HAVE_TZNAME</code> is nonzero) to learn the correct time + use <code>strftime</code> with a <code>%Z</code> conversion specification + to learn the correct time zone abbreviation to use. </li> <li> diff --git a/contrib/tzcode/tz-link.html b/contrib/tzcode/tz-link.html index be2aae5489d6..ad2cc972a4f9 100644 --- a/contrib/tzcode/tz-link.html +++ b/contrib/tzcode/tz-link.html @@ -194,9 +194,9 @@ After obtaining the code and data files, see the The code lets you compile the <code><abbr>tz</abbr></code> source files into machine-readable binary files, one for each location. The binary files are in a special format specified by -<a href="https://datatracker.ietf.org/doc/html/8536">The +<a href="https://www.rfc-editor.org/rfc/9636">The Time Zone Information Format (<abbr>TZif</abbr>)</a> -(Internet <abbr title="Request For Comments">RFC</abbr> 8536). +(Internet <abbr title="Request For Comments">RFC</abbr> 9636). The code also lets you read a <abbr>TZif</abbr> file and interpret timestamps for that location.</p> @@ -260,7 +260,7 @@ Studio Code</a>. </p> <p> For further information about updates, please see -<a href="https://datatracker.ietf.org/doc/html/rfc6557">Procedures for +<a href="https://www.rfc-editor.org/rfc/rfc6557">Procedures for Maintaining the Time Zone Database</a> (Internet <abbr>RFC</abbr> 6557). More detail can be found in <a href="theory.html">Theory and pragmatics of the @@ -379,26 +379,26 @@ calculates the current time difference between locations.</li> <li>The <a href="https://www.ietf.org">Internet Engineering Task Force</a>'s <a href="https://datatracker.ietf.org/wg/tzdist/charter/">Time Zone Data Distribution Service (tzdist) working group</a> defined <a -href="https://datatracker.ietf.org/doc/html/rfc7808">TZDIST</a> +href="https://www.rfc-editor.org/rfc/rfc7808">TZDIST</a> (Internet <abbr>RFC</abbr> 7808), a time zone data distribution service, -along with <a href="https://datatracker.ietf.org/doc/html/rfc7809">CalDAV</a> +along with <a href="https://www.rfc-editor.org/rfc/rfc7809">CalDAV</a> (Internet <abbr>RFC</abbr> 7809), a calendar access protocol for transferring time zone data by reference. <a href="https://devguide.calconnect.org/Time-Zones/TZDS/">TZDIST implementations</a> are available. The <a href="https://www.ietf.org/mailman/listinfo/tzdist-bis">tzdist-bis mailing list</a> discusses possible extensions.</li> -<li>The <a href="https://datatracker.ietf.org/doc/html/rfc5545"> +<li>The <a href="https://www.rfc-editor.org/rfc/rfc5545"> Internet Calendaring and Scheduling Core Object Specification (iCalendar)</a> (Internet <abbr>RFC</abbr> 5445) covers time zone data; see its VTIMEZONE calendar component. The iCalendar format requires specialized parsers and generators; a -variant <a href="https://datatracker.ietf.org/doc/html/rfc6321">xCal</a> +variant <a href="https://www.rfc-editor.org/rfc/rfc6321">xCal</a> (Internet <abbr>RFC</abbr> 6321) uses <a href="https://www.w3.org/XML/"><abbr title="Extensible Markup Language">XML</abbr></a> format, and a variant -<a href="https://datatracker.ietf.org/doc/html/rfc7265">jCal</a> +<a href="https://www.rfc-editor.org/rfc/rfc7265">jCal</a> (Internet <abbr>RFC</abbr> 7265) uses <a href="https://www.json.org/json-en.html"><abbr title="JavaScript Object Notation">JSON</abbr></a> format.</li> @@ -935,7 +935,13 @@ with perhaps the best-documented history of clock adjustments.</dd> <dt>United States</dt> <dd>The Department of Transportation's <a href="https://www.transportation.gov/regulations/recent-time-zone-proceedings">Recent -Time Zone Proceedings</a> lists changes to time zone boundaries.</dd> +Time Zone Proceedings</a> lists changes to +official written time zone boundaries, and its <a +href="https://geodata.bts.gov/datasets/usdot::time-zones/about">Time +Zones dataset</a> maps current boundaries. +These boundaries are only for standard time, so the current map puts +all of Arizona in one time zone even though part of Arizona +observes <abbr>DST</abbr> and part does not.</dd> <dt>Uruguay</dt> <dd>The Oceanography, Hydrography, and Meteorology Service of the Uruguayan Navy (SOHMA) publishes an annual <a @@ -979,6 +985,14 @@ a Sleep Research Society position statement</a>. doi:<a href="https://doi.org/10.1093/sleep/zsac236">10.1093/sleep/zsac236</a>. After reviewing the scientific literature, the Sleep Research Society advocates permanent standard time due to its health benefits. +<li>Neumann P, von Blanckenburg K. <a +href="https://journals.sagepub.com/doi/full/10.1177/0961463X241310562">What +time will it be? A comprehensive literature review on daylight saving time</a>. +<em>Time Soc</em>. 2025-01-21. +doi:<a href="https://doi.org/10.1177/0961463X241310562">10.1177/0961463X241310562</a>. +This reviews DST's effects on electricity, health, crime, road safety, +and the economy, focusing on research since 2010, and concludes that +year-round standard time is preferable overall. <li>Rishi MA, Cheng JY, Strang AR <em>et al</em>. <a href="https://jcsm.aasm.org/doi/10.5664/jcsm.10898">Permanent standard time is the optimal choice for health and safety: @@ -994,7 +1008,8 @@ should we abolish Daylight Saving Time?</a> <em>J Biol Rhythms.</em> 2019;34(3):227–230. doi:<a href="https://doi.org/10.1177/0748730419854197">10.1177/0748730419854197</a>. The Society for Research on Biological Rhythms -opposes DST changes and permanent DST, and advocates that governments adopt +opposes <abbr>DST</abbr> changes and permanent <abbr>DST</abbr>, +and advocates that governments adopt "permanent Standard Time for the health and safety of their citizens".</li> </ul> </section> @@ -1023,7 +1038,7 @@ title="Institute of Electrical and Electronics Engineers">IEEE</abbr> 1588) can achieve submicrosecond clock accuracy on a local area network with special-purpose hardware.</li> <li><a -href="https://datatracker.ietf.org/doc/html/rfc4833">Timezone +href="https://www.rfc-editor.org/rfc/rfc4833">Timezone Options for <abbr title="Dynamic Host Configuration Protocol">DHCP</abbr></a> (Internet <abbr>RFC</abbr> 4833) specifies a <a @@ -1105,7 +1120,7 @@ the abovementioned <abbr>NTP</abbr> implementations, <a href="https://github.com/google/unsmear">supports</a> conversion between <abbr>UTC</abbr> and smeared <abbr>POSIX</abbr> timestamps, and is used by major cloud service providers. However, according to -<a href="https://datatracker.ietf.org/doc/html/rfc8633#section-3.7.1">§3.7.1 of +<a href="https://www.rfc-editor.org/rfc/rfc8633#section-3.7.1">§3.7.1 of Network Time Protocol Best Current Practices</a> (Internet <abbr>RFC</abbr> 8633), leap smearing is not suitable for applications requiring accurate <abbr>UTC</abbr> or civil time, @@ -1165,16 +1180,16 @@ interchange – Part 1: Basic rules</em></a>.</li> <a href="https://www.w3.org/TR/xmlschema/#dateTime"><abbr>XML</abbr> Schema: Datatypes – dateTime</a> specifies a format inspired by <abbr>ISO</abbr> 8601 that is in common use in <abbr>XML</abbr> data.</li> -<li><a href="https://datatracker.ietf.org/doc/html/rfc5322#section-3.3">§3.3 of +<li><a href="https://www.rfc-editor.org/rfc/rfc5322#section-3.3">§3.3 of Internet Message Format</a> (Internet <abbr>RFC</abbr> 5322) specifies the time notation used in email and <a href="https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol"><abbr>HTTP</abbr></a> headers.</li> <li> -<a href="https://datatracker.ietf.org/doc/html/rfc3339">Date and Time +<a href="https://www.rfc-editor.org/rfc/rfc3339">Date and Time on the Internet: Timestamps</a> (Internet <abbr>RFC</abbr> 3339) specifies an <abbr>ISO</abbr> 8601 profile for use in new Internet protocols. -An extension, <a href="https://datatracker.ietf.org/doc/html/rfc9557">Date +An extension, <a href="https://www.rfc-editor.org/rfc/rfc9557">Date and Time on the Internet: Timestamps with Additional Information</a> (Internet <abbr>RFC</abbr> 9557) extends this profile to let you specify the <code><abbr>tzdb</abbr></code> timezone of a timestamp diff --git a/contrib/tzcode/tzfile.5 b/contrib/tzcode/tzfile.5 index 63bda4114388..66d169fc5302 100644 --- a/contrib/tzcode/tzfile.5 +++ b/contrib/tzcode/tzfile.5 @@ -11,7 +11,7 @@ The timezone information files used by .Xr tzset 3 are found under .Pa /usr/share/zoneinfo . -These files use the format described in Internet RFC 8536. +These files use the format described in Internet RFC 9636. Each file is a sequence of 8-bit bytes. In a file, a binary integer is represented by a sequence of one or more bytes in network order (bigendian, or high-order byte first), @@ -107,7 +107,7 @@ and serves as an index into the array of time zone abbreviation bytes that follow the .Vt ttinfo -entries in the file; if the designated string is "\*-00", the +entries in the file; if the designated string is "\-00", the .Vt ttinfo entry is a placeholder indicating that local time is unspecified. The @@ -128,7 +128,7 @@ The byte strings can overlap if one is a suffix of the other. The encoding of these strings is not specified. .It Va tzh_leapcnt pairs of four-byte values, written in network byte order; -the first value of each pair gives the nonnegative time +the first value of each pair gives the non-negative time (as returned by .Xr time 3 ) at which a leap second occurs or at which the leap second table expires; @@ -141,7 +141,7 @@ Each pair denotes one leap second, either positive or negative, except that if the last pair has the same correction as the previous one, the last pair denotes the leap second table's expiration time. Each leap second is at the end of a UTC calendar month. -The first leap second has a nonnegative occurrence time, +The first leap second has a non-negative occurrence time, and is a positive leap second if and only if its correction is positive; the correction for each leap second after the first differs from the previous leap second by either 1 for a positive leap second, @@ -168,7 +168,7 @@ The standard/wall and UT/local indicators were designed for transforming a TZif file's transition times into transitions appropriate for another time zone specified via a proleptic TZ string that lacks rules. -For example, when TZ="EET\*-2EEST" and there is no TZif file "EET\*-2EEST", +For example, when TZ="EET\-2EEST" and there is no TZif file "EET\-2EEST", the idea was to adapt the transition times from a TZif file with the well-known name "posixrules" that is present only for this purpose and is a copy of the file "Europe/Brussels", a file with a different UT offset. @@ -177,7 +177,7 @@ the default rules are installation-dependent, and no implementation is known to support this feature for timestamps past 2037, so users desiring (say) Greek time should instead specify TZ="Europe/Athens" for better historical coverage, falling back on -TZ="EET\*-2EEST,M3.5.0/3,M10.5.0/4" if POSIX conformance is required +TZ="EET\-2EEST,M3.5.0/3,M10.5.0/4" if POSIX conformance is required and older timestamps need not be handled accurately. .Pp The @@ -203,7 +203,7 @@ after the last transition time stored in the file or for all instants if the file has no transitions. The TZ string is empty (i.e., nothing between the newlines) if there is no proleptic representation for such instants. -If nonempty, the TZ string must agree with the local time +If non-empty, the TZ string must agree with the local time type after the last transition time if present in the eight-byte data; for example, given the string .Dq "WET0WEST,M3.5.0/1,M10.5.0" @@ -218,7 +218,7 @@ the earliest transition time. For version-3-format timezone files, a TZ string (see .Xr newtzset 3 ) may use the following POSIX.1-2024 extensions to POSIX.1-2017: -First, as in TZ="<\*-02>2<\*-01>,M3.5.0/\*-1,M10.5.0/0", +First, as in TZ="<\-02>2<\-01>,M3.5.0/\-1,M10.5.0/0", the hours part of its transition times may be signed and range from \-167 through 167 instead of being limited to unsigned values from 0 through 24. @@ -275,7 +275,7 @@ time did not exist (possibly with an error indication). Time zone designations should consist of at least three (3) and no more than six (6) ASCII characters from the set of alphanumerics, -.Dq "\*-" , +.Dq "\-" , and .Dq "+" . This is for compatibility with POSIX requirements for @@ -300,16 +300,16 @@ through 60 instead of the usual 59; the UTC offset is unaffected. This section documents common problems in reading or writing TZif files. Most of these are problems in generating TZif files for use by older readers. -The goals of this section are: +The goals of this section are to help: .Bl -bullet .It -to help TZif writers output files that avoid common +TZif writers output files that avoid common pitfalls in older or buggy TZif readers, .It -to help TZif readers avoid common pitfalls when reading +TZif readers avoid common pitfalls when reading files generated by future TZif writers, and .It -to help any future specification authors see what sort of +any future specification authors see what sort of problems arise when the TZif format is changed. .El .Pp @@ -320,9 +320,9 @@ reader was designed for. When complete compatibility was not achieved, an attempt was made to limit glitches to rarely used timestamps and allow simple partial workarounds in writers designed to generate -new-version data useful even for older-version readers. +newer-version data useful even for older-version readers. This section attempts to document these compatibility issues and -workarounds, as well as to document other common bugs in +workarounds as well as documenting other common bugs in readers. .Pp Interoperability problems with TZif include the following: @@ -355,15 +355,15 @@ for two time zones east, e.g., for a time zone with a never-used standard time (XXX, \-03) and negative daylight saving time (EDT, \-04) all year. Alternatively, -as a partial workaround a writer can substitute standard time +as a partial workaround, a writer can substitute standard time for the next time zone east \(en e.g., .Dq "AST4" for permanent Atlantic Standard Time (\-04). .It -Some readers designed for version 2 or 3, and that require strict -conformance to RFC 8536, reject version 4 files whose leap second -tables are truncated at the start or that end in expiration times. +Some readers designed for version 2 or 3 and that require strict +conformance to RFC 9636 reject version 4 files whose leap second +tables are truncated at the start or end in expiration times. .It Some readers ignore the footer, and instead predict future timestamps from the time type of the last transition. @@ -378,7 +378,7 @@ and even for current timestamps it can fail for settings like TZ="Africa/Casablanca". This corresponds to a TZif file containing explicit transitions through the year 2087, followed by a footer containing the TZ string -.Dq <+01>\*-1 , +.Dq <+01>\-1 , which should be used only for timestamps after the last explicit transition. .It @@ -389,7 +389,7 @@ As a partial workaround, a writer can output a dummy (no-op) first transition at an early time. .It Some readers mishandle timestamps before the first -transition that has a timestamp not less than \-2**31. +transition that has a timestamp that is not less than \-2**31. Readers that support only 32-bit timestamps are likely to be more prone to this problem, for example, when they process 64-bit transitions only some of which are representable in 32 @@ -401,7 +401,7 @@ Some readers mishandle a transition if its timestamp has the minimum possible signed 64-bit value. Timestamps less than \-2**59 are not recommended. .It -Some readers mishandle TZ strings that +Some readers mishandle proleptic TZ strings that contain .Dq "<" or @@ -418,9 +418,9 @@ non-ASCII characters. These characters are not recommended. .It Some readers may mishandle time zone abbreviations that -contain fewer than 3 or more than 6 characters, or that +contain fewer than 3 or more than 6 characters or that contain ASCII characters other than alphanumerics, -.Dq "\*-", +.Dq "\-", and .Dq "+". These abbreviations are not recommended. @@ -430,7 +430,7 @@ daylight-saving time UT offsets that are less than the UT offsets for the corresponding standard time. These readers do not support locations like Ireland, which uses the equivalent of the TZ string -.Dq "IST\*-1GMT0,M10.5.0,M3.5.0/1", +.Dq "IST\-1GMT0,M10.5.0,M3.5.0/1", observing standard time (IST, +01) in summer and daylight saving time (GMT, +00) in winter. As a partial workaround, a writer can output data for the @@ -443,7 +443,7 @@ abbreviations correctly. .It Some readers generate ambiguous timestamps for positive leap seconds that occur when the UTC offset is not a multiple of 60 seconds. -For example, in a timezone with UTC offset +01:23:45 and with +For example, with UTC offset +01:23:45 and a positive leap second 78796801 (1972-06-30 23:59:60 UTC), some readers will map both 78796800 and 78796801 to 01:23:45 local time the next day instead of mapping the latter to 01:23:46, and they will map 78796815 to @@ -462,15 +462,15 @@ Developers of distributed applications should keep this in mind if they need to deal with pre-1970 data. .It Some readers mishandle timestamps before the first -transition that has a nonnegative timestamp. +transition that has a non-negative timestamp. Readers that do not support negative timestamps are likely to be more prone to this problem. .It Some readers mishandle time zone abbreviations like -.Dq "\*-08" +.Dq "\-08" that contain -.Dq "+" , -.Dq "\*-" , +.Dq "+", +.Dq "\-", or digits. .It Some readers mishandle UT offsets that are out of the @@ -479,7 +479,7 @@ support locations like Kiritimati that are outside this range. .It Some readers mishandle UT offsets in the range [\-3599, \-1] -seconds from UT, because they integer-divide the offset by +seconds from UT because they integer-divide the offset by 3600 to get 0 and then display the hour part as .Dq "+00" . .It @@ -498,8 +498,8 @@ of one hour, or of 15 minutes, or of 1 minute. .%A P. Eggert .%A K. Murchison .%T "The Time Zone Information Format (TZif)" -.%R RFC 8536 -.%D February 2019 -.%U https://datatracker.ietf.org/doc/html/rfc8536 -.%U https://doi.org/10.17487/RFC8536 +.%R RFC 9636 +.%D October 2024 +.%U https://datatracker.ietf.org/doc/html/rfc9636 +.%U https://doi.org/10.17487/RFC9636 .Re diff --git a/contrib/tzcode/tzfile.h b/contrib/tzcode/tzfile.h index c09f39465914..55867b5c260c 100644 --- a/contrib/tzcode/tzfile.h +++ b/contrib/tzcode/tzfile.h @@ -28,7 +28,7 @@ #endif /* !defined TZDEFRULES */ -/* See Internet RFC 8536 for more details about the following format. */ +/* See Internet RFC 9636 for more details about the following format. */ /* ** Each file begins with. . . diff --git a/contrib/tzcode/tzselect.8 b/contrib/tzcode/tzselect.8 index ee031614f3ed..b83f702d5e0d 100644 --- a/contrib/tzcode/tzselect.8 +++ b/contrib/tzcode/tzselect.8 @@ -4,8 +4,6 @@ .SH NAME tzselect \- select a timezone .SH SYNOPSIS -.ie \n(.g .ds - \f(CR-\fP -.el .ds - \- .ds d " degrees .ds m " minutes .ds s " seconds @@ -20,15 +18,15 @@ tzselect \- select a timezone .\} .B tzselect [ -.B \*-c +.B \-c .I coord ] [ -.B \*-n +.B \-n .I limit ] [ -.B \*-\*-help +.B \-\-help ] [ -.B \*-\*-version +.B \-\-version ] .SH DESCRIPTION The @@ -40,7 +38,7 @@ The output is suitable as a value for the TZ environment variable. All interaction with the user is done via standard input and standard error. .SH OPTIONS .TP -.BI "\*-c " coord +.BI "\-c " coord Instead of asking for continent and then country and then city, ask for selection from time zones whose largest cities are closest to the location with geographical coordinates @@ -70,27 +68,27 @@ seconds, with any trailing fractions represent fractional minutes or .I SS is present) seconds. The decimal point is that of the current locale. For example, in the (default) C locale, -.B "\*-c\ +40.689\*-074.045" +.B "\-c\ +40.689\-074.045" specifies 40.689\*d\*_N, 74.045\*d\*_W, -.B "\*-c\ +4041.4\*-07402.7" +.B "\-c\ +4041.4\-07402.7" specifies 40\*d\*_41.4\*m\*_N, 74\*d\*_2.7\*m\*_W, and -.B "\*-c\ +404121\*-0740240" +.B "\-c\ +404121\-0740240" specifies 40\*d\*_41\*m\*_21\*s\*_N, 74\*d\*_2\*m\*_40\*s\*_W. If .I coord is not one of the documented forms, the resulting behavior is unspecified. .TP -.BI "\*-n " limit +.BI "\-n " limit When -.B \*-c +.B \-c is used, display the closest .I limit locations (default 10). .TP -.B "\*-\*-help" +.B "\-\-help" Output help information and exit. .TP -.B "\*-\*-version" +.B "\-\-version" Output version information and exit. .SH "ENVIRONMENT VARIABLES" .TP diff --git a/contrib/tzcode/version b/contrib/tzcode/version index 699e50d4d38e..ef468adcecf9 100644 --- a/contrib/tzcode/version +++ b/contrib/tzcode/version @@ -1 +1 @@ -2024b +2025b diff --git a/contrib/tzcode/zdump.8 b/contrib/tzcode/zdump.8 index 7a78f6b9c040..c5cb092db16f 100644 --- a/contrib/tzcode/zdump.8 +++ b/contrib/tzcode/zdump.8 @@ -28,6 +28,14 @@ The program prints the current time in each .Ar timezone named on the command line. +A +.Ar timezone +of +.Li - +is treated as if it were +.Pa /dev/stdin ; +this can be used to pipe TZif data into +.Nm . .Pp The following options are available: .Bl -tag -width indent @@ -106,7 +114,7 @@ then a line where .Ar string is a double-quoted string giving the timezone, a second line -.Dq "\*- \*- \fIinterval\fP" +.Dq "\- \- \fIinterval\fP" describing the time interval before the first transition if any, and zero or more following lines .Dq "\fIdate time interval\fP", @@ -138,11 +146,11 @@ the seconds are omitted if they are zero, and the minutes are also omitted if they are also zero. Positive UT offsets are east of Greenwich. -The UT offset \*-00 denotes a UT +The UT offset \-00 denotes a UT placeholder in areas where the actual offset is unspecified; by convention, this occurs when the UT offset is zero and the time zone abbreviation begins with -.Dq "-" +.Dq "\-" or is .Dq "zzz". .Pp diff --git a/contrib/tzcode/zdump.c b/contrib/tzcode/zdump.c index a42c337e6d44..a8a8f5aa42ca 100644 --- a/contrib/tzcode/zdump.c +++ b/contrib/tzcode/zdump.c @@ -14,10 +14,6 @@ #include "private.h" #include <stdio.h> -#ifndef HAVE_SNPRINTF -# define HAVE_SNPRINTF (!PORT_TO_C89 || 199901 <= __STDC_VERSION__) -#endif - #ifndef HAVE_LOCALTIME_R # define HAVE_LOCALTIME_R 1 #endif @@ -148,17 +144,6 @@ sumsize(ptrdiff_t a, ptrdiff_t b) size_overflow(); } -/* Return the size of of the string STR, including its trailing NUL. - Report an error and exit if this would exceed INDEX_MAX which means - pointer subtraction wouldn't work. */ -static ptrdiff_t -xstrsize(char const *str) -{ - size_t len = strlen(str); - if (len < INDEX_MAX) - return len + 1; - size_overflow(); -} /* Return a pointer to a newly allocated buffer of size SIZE, exiting on failure. SIZE should be positive. */ @@ -266,7 +251,7 @@ tzalloc(char const *val) static ptrdiff_t fakeenv0size; void *freeable = NULL; char **env = fakeenv, **initial_environ; - ptrdiff_t valsize = xstrsize(val); + ptrdiff_t valsize = strlen(val) + 1; if (fakeenv0size < valsize) { char **e = environ, **to; ptrdiff_t initial_nenvptrs = 1; /* Counting the trailing NULL pointer. */ @@ -427,7 +412,7 @@ saveabbr(char **buf, ptrdiff_t *bufalloc, struct tm const *tmp) if (HAVE_LOCALTIME_RZ) return ab; else { - ptrdiff_t absize = xstrsize(ab); + ptrdiff_t absize = strlen(ab) + 1; if (*bufalloc < absize) { free(*buf); @@ -489,6 +474,7 @@ main(int argc, char *argv[]) register time_t cuthitime; time_t now; bool iflag = false; + size_t arglenmax = 0; cutlotime = absolute_min_time; cuthitime = absolute_max_time; @@ -588,15 +574,21 @@ main(int argc, char *argv[]) now = time(NULL); now |= !now; } - longest = 0; for (i = optind; i < argc; i++) { size_t arglen = strlen(argv[i]); - if (longest < arglen) - longest = min(arglen, INT_MAX); + if (arglenmax < arglen) + arglenmax = arglen; } + if (!HAVE_SETENV && INDEX_MAX <= arglenmax) + size_overflow(); + longest = min(arglenmax, INT_MAX - 2); for (i = optind; i < argc; ++i) { - timezone_t tz = tzalloc(argv[i]); + /* Treat "-" as standard input on platforms with /dev/stdin. + It's not worth the bother of supporting "-" on other + platforms, as that would need temp files. */ + timezone_t tz = tzalloc(strcmp(argv[i], "-") == 0 + ? "/dev/stdin" : argv[i]); char const *ab; time_t t; struct tm tm, newtm; @@ -697,7 +689,7 @@ yeartot(intmax_t y) return absolute_max_time; seconds = diff400 * SECSPER400YEARS; years = diff400 * 400; - } else { + } else { seconds = isleap(myy) ? SECSPERLYEAR : SECSPERNYEAR; years = 1; } @@ -928,13 +920,10 @@ showextrema(timezone_t tz, char *zone, time_t lo, struct tm *lotmp, time_t hi) } } -#if HAVE_SNPRINTF -# define my_snprintf snprintf -#else +/* On pre-C99 platforms, a snprintf substitute good enough for us. */ +#if !HAVE_SNPRINTF # include <stdarg.h> - -/* A substitute for snprintf that is good enough for zdump. */ -static int +ATTRIBUTE_FORMAT((printf, 3, 4)) static int my_snprintf(char *s, size_t size, char const *format, ...) { int n; @@ -962,6 +951,7 @@ my_snprintf(char *s, size_t size, char const *format, ...) va_end(args); return n; } +# define snprintf my_snprintf #endif /* Store into BUF, of size SIZE, a formatted local time taken from *TM. @@ -976,10 +966,10 @@ format_local_time(char *buf, ptrdiff_t size, struct tm const *tm) { int ss = tm->tm_sec, mm = tm->tm_min, hh = tm->tm_hour; return (ss - ? my_snprintf(buf, size, "%02d:%02d:%02d", hh, mm, ss) + ? snprintf(buf, size, "%02d:%02d:%02d", hh, mm, ss) : mm - ? my_snprintf(buf, size, "%02d:%02d", hh, mm) - : my_snprintf(buf, size, "%02d", hh)); + ? snprintf(buf, size, "%02d:%02d", hh, mm) + : snprintf(buf, size, "%02d", hh)); } /* Store into BUF, of size SIZE, a formatted UT offset for the @@ -1014,10 +1004,10 @@ format_utc_offset(char *buf, ptrdiff_t size, struct tm const *tm, time_t t) mm = off / 60 % 60; hh = off / 60 / 60; return (ss || 100 <= hh - ? my_snprintf(buf, size, "%c%02ld%02d%02d", sign, hh, mm, ss) + ? snprintf(buf, size, "%c%02ld%02d%02d", sign, hh, mm, ss) : mm - ? my_snprintf(buf, size, "%c%02ld%02d", sign, hh, mm) - : my_snprintf(buf, size, "%c%02ld", sign, hh)); + ? snprintf(buf, size, "%c%02ld%02d", sign, hh, mm) + : snprintf(buf, size, "%c%02ld", sign, hh)); } /* Store into BUF (of size SIZE) a quoted string representation of P. @@ -1120,7 +1110,7 @@ istrftime(char *buf, ptrdiff_t size, char const *time_fmt, for (abp = ab; is_alpha(*abp); abp++) continue; len = (!*abp && *ab - ? my_snprintf(b, s, "%s", ab) + ? snprintf(b, s, "%s", ab) : format_quoted_string(b, s, ab)); if (s <= len) return false; @@ -1128,7 +1118,7 @@ istrftime(char *buf, ptrdiff_t size, char const *time_fmt, } formatted_len = (tm->tm_isdst - ? my_snprintf(b, s, &"\t\t%d"[show_abbr], tm->tm_isdst) + ? snprintf(b, s, &"\t\t%d"[show_abbr], tm->tm_isdst) : 0); } break; diff --git a/contrib/tzcode/zic.8 b/contrib/tzcode/zic.8 index 3804096dd6f6..d83ff7c4a0b1 100644 --- a/contrib/tzcode/zic.8 +++ b/contrib/tzcode/zic.8 @@ -112,13 +112,13 @@ Link \fItimezone\fP posixrules If .Ar timezone is -.Dq "\*-" +.Dq "\-" (the default), any already-existing link is removed. .Pp Unless .Ar timezone is -.Dq "\*-" , +.Dq "\-" , this option is obsolete and poorly supported. Among other things it should not be used for timestamps after the year 2037, and it should not be combined with @@ -148,6 +148,10 @@ omits data intended for negative timestamps (i.e., before the Epoch), and .Fl r @0/@2147483648 outputs data intended only for nonnegative timestamps that fit into 31-bit signed integers. +On platforms with GNU +.Nm date , +.Dq "zic \-r @$(date +%s)" +omits data intended for past timestamps. Although this option typically reduces the output file's size, the size can increase due to the need to represent the timestamp range boundaries, particularly if @@ -366,7 +370,15 @@ separate script to further restrict in which of years the rule would apply. .It IN Names the month in which the rule takes effect. -Month names may be abbreviated. +Month names may be abbreviated as mentioned previously; +for example, January can appear as +.Dq January , +.Dq JANU +or +.Dq Ja , +but not as +.Dq j +which would be ambiguous with both June and July. .It ON Gives the day on which the rule takes effect. Recognized forms include: @@ -389,7 +401,12 @@ or a weekday name preceded by .Dq "last" (e.g., .Ql "lastSunday" ) -may be abbreviated or spelled out in full. +may be abbreviated as mentioned previously, +e.g., +.Dq Su +for Sunday and +.Dq lastsa +for the last Saturday. There must be no white space characters within the .Ar ON field. @@ -540,7 +557,7 @@ field, giving the amount of time to be added to local standard time and whether the resulting time is standard or daylight saving. Standard time applies if this field is -.Ql \*- +.Ql \- or for timestamps occurring before any rule takes effect. When an amount of time is given, only the sum of standard time and this amount matters. diff --git a/contrib/tzcode/zic.c b/contrib/tzcode/zic.c index 2605f65dcd23..80902ce534a1 100644 --- a/contrib/tzcode/zic.c +++ b/contrib/tzcode/zic.c @@ -526,19 +526,19 @@ memcheck(void *ptr) } static void * -emalloc(size_t size) +xmalloc(size_t size) { return memcheck(malloc(size)); } static void * -erealloc(void *ptr, size_t size) +xrealloc(void *ptr, size_t size) { return memcheck(realloc(ptr, size)); } static char * -estrdup(char const *str) +xstrdup(char const *str) { return memcheck(strdup(str)); } @@ -567,7 +567,7 @@ growalloc(void *ptr, ptrdiff_t itemsize, ptrdiff_t nitems, { return (nitems < *nitems_alloc ? ptr - : erealloc(ptr, grow_nitems_alloc(nitems_alloc, itemsize))); + : xrealloc(ptr, grow_nitems_alloc(nitems_alloc, itemsize))); } /* @@ -654,6 +654,8 @@ close_file(FILE *stream, char const *dir, char const *name, char const *e = (ferror(stream) ? _("I/O error") : fclose(stream) != 0 ? strerror(errno) : NULL); if (e) { + if (name && *name == '/') + dir = NULL; fprintf(stderr, "%s: %s%s%s%s%s\n", progname, dir ? dir : "", dir ? "/" : "", name ? name : "", name ? ": " : "", @@ -961,6 +963,9 @@ static mode_t mflag = (S_IRUSR | S_IRGRP | S_IROTH | S_IWUSR); static const char * tzdefault; +/* True if DIRECTORY ends in '/'. */ +static bool directory_ends_in_slash; + /* -1 if the TZif output file should be slim, 0 if default, 1 if the output should be fat for backward compatibility. ZIC_BLOAT_DEFAULT determines the default. */ @@ -1166,6 +1171,7 @@ _("invalid file mode")); return EXIT_FAILURE; associate(); change_directory(directory); + directory_ends_in_slash = directory[strlen(directory) - 1] == '/'; catch_signals(); for (i = 0; i < nzones; i = j) { /* @@ -1353,7 +1359,7 @@ random_dirent(char const **name, char **namealloc) uint_fast64_t unfair_min = - ((UINTMAX_MAX % base__6 + 1) % base__6); if (!dst) { - dst = emalloc(size_sum(dirlen, prefixlen + suffixlen + 1)); + dst = xmalloc(size_sum(dirlen, prefixlen + suffixlen + 1)); memcpy(dst, src, dirlen); memcpy(dst + dirlen, prefix, prefixlen); dst[dirlen + prefixlen + suffixlen] = '\0'; @@ -1370,6 +1376,20 @@ random_dirent(char const **name, char **namealloc) } } +/* For diagnostics the directory, and file name relative to that + directory, respectively. A diagnostic routine can name FILENAME by + outputting diagdir(FILENAME), then diagslash(FILENAME), then FILENAME. */ +static char const * +diagdir(char const *filename) +{ + return *filename == '/' ? "" : directory; +} +static char const * +diagslash(char const *filename) +{ + return &"/"[*filename == '/' || directory_ends_in_slash]; +} + /* Prepare to write to the file *OUTNAME, using *TEMPNAME to store the name of the temporary file that will eventually be renamed to *OUTNAME. Assign the temporary file's name to both *OUTNAME and @@ -1406,8 +1426,9 @@ open_outfile(char const **outname, char **tempname) } else if (fopen_errno == EEXIST) random_dirent(outname, tempname); else { - fprintf(stderr, _("%s: Can't create %s/%s: %s\n"), - progname, directory, *outname, strerror(fopen_errno)); + fprintf(stderr, _("%s: Can't create %s%s%s: %s\n"), + progname, diagdir(*outname), diagslash(*outname), *outname, + strerror(fopen_errno)); exit(EXIT_FAILURE); } } @@ -1424,9 +1445,10 @@ rename_dest(char *tempname, char const *name) if (tempname) { if (rename(tempname, name) != 0) { int rename_errno = errno; - (void)remove(tempname); - fprintf(stderr, _("%s: rename to %s/%s: %s\n"), - progname, directory, name, strerror(rename_errno)); + remove(tempname); + fprintf(stderr, _("%s: rename to %s%s%s: %s\n"), + progname, diagdir(name), diagslash(name), name, + strerror(rename_errno)); exit(EXIT_FAILURE); } free(tempname); @@ -1436,7 +1458,8 @@ rename_dest(char *tempname, char const *name) /* Create symlink contents suitable for symlinking TARGET to LINKNAME, as a freshly allocated string. TARGET should be a relative file name, and is relative to the global variable DIRECTORY. LINKNAME can be either - relative or absolute. */ + relative or absolute. Return a null pointer if the symlink contents + was not computed because LINKNAME is absolute but DIRECTORY is not. */ static char * relname(char const *target, char const *linkname) { @@ -1449,8 +1472,10 @@ relname(char const *target, char const *linkname) size_t len = strlen(directory); size_t lenslash = len + (len && directory[len - 1] != '/'); size_t targetsize = strlen(target) + 1; + if (*directory != '/') + return NULL; linksize = size_sum(lenslash, targetsize); - f = result = emalloc(linksize); + f = result = xmalloc(linksize); memcpy(result, directory, len); result[len] = '/'; memcpy(result + lenslash, target, targetsize); @@ -1464,7 +1489,7 @@ relname(char const *target, char const *linkname) dotdotetcsize = size_sum(size_product(dotdots, 3), taillen + 1); if (dotdotetcsize <= linksize) { if (!result) - result = emalloc(dotdotetcsize); + result = xmalloc(dotdotetcsize); for (i = 0; i < dotdots; i++) memcpy(result + 3 * i, "../", 3); memmove(result + 3 * dotdots, f + dir_len, taillen + 1); @@ -1500,8 +1525,9 @@ dolink(char const *target, char const *linkname, bool staysymlink) return; else { char const *e = strerror(errno); - fprintf(stderr, _("%s: Can't remove %s/%s: %s\n"), - progname, directory, linkname, e); + fprintf(stderr, _("%s: Can't remove %s%s%s: %s\n"), + progname, diagdir(linkname), diagslash(linkname), linkname, + e); exit(EXIT_FAILURE); } } @@ -1544,8 +1570,9 @@ dolink(char const *target, char const *linkname, bool staysymlink) mkdirs(linkname, true); linkdirs_made = true; } else { - fprintf(stderr, _("%s: Can't link %s/%s to %s/%s: %s\n"), - progname, directory, target, directory, outname, + fprintf(stderr, _("%s: Can't link %s%s%s to %s%s%s: %s\n"), + progname, diagdir(target), diagslash(target), target, + diagdir(outname), diagslash(outname), outname, strerror(link_errno)); exit(EXIT_FAILURE); } @@ -1554,21 +1581,23 @@ dolink(char const *target, char const *linkname, bool staysymlink) bool absolute = *target == '/'; char *linkalloc = absolute ? NULL : relname(target, linkname); char const *contents = absolute ? target : linkalloc; - int symlink_errno; + int symlink_errno = -1; - while (true) { - if (symlink(contents, outname) == 0) { - symlink_errno = 0; - break; + if (contents) { + while (true) { + if (symlink(contents, outname) == 0) { + symlink_errno = 0; + break; + } + symlink_errno = errno; + if (symlink_errno == EEXIST) + random_dirent(&outname, &tempname); + else if (symlink_errno == ENOENT && !linkdirs_made) { + mkdirs(linkname, true); + linkdirs_made = true; + } else + break; } - symlink_errno = errno; - if (symlink_errno == EEXIST) - random_dirent(&outname, &tempname); - else if (symlink_errno == ENOENT && !linkdirs_made) { - mkdirs(linkname, true); - linkdirs_made = true; - } else - break; } free(linkalloc); if (symlink_errno == 0) { @@ -1581,8 +1610,8 @@ dolink(char const *target, char const *linkname, bool staysymlink) fp = fopen(target, "rb"); if (!fp) { char const *e = strerror(errno); - fprintf(stderr, _("%s: Can't read %s/%s: %s\n"), - progname, directory, target, e); + fprintf(stderr, _("%s: Can't read %s%s%s: %s\n"), + progname, diagdir(target), diagslash(target), target, e); exit(EXIT_FAILURE); } tp = open_outfile(&outname, &tempname); @@ -1593,6 +1622,8 @@ dolink(char const *target, char const *linkname, bool staysymlink) if (link_errno != ENOTSUP) warning(_("copy used because hard link failed: %s"), strerror(link_errno)); + else if (symlink_errno < 0) + warning(_("copy used because symbolic link not obvious")); else if (symlink_errno != ENOTSUP) warning(_("copy used because symbolic link failed: %s"), strerror(symlink_errno)); @@ -1906,8 +1937,8 @@ inrule(char **fields, int nfields) fields[RF_COMMAND], fields[RF_MONTH], fields[RF_DAY], fields[RF_TOD])) return; - r.r_name = estrdup(fields[RF_NAME]); - r.r_abbrvar = estrdup(fields[RF_ABBRVAR]); + r.r_name = xstrdup(fields[RF_NAME]); + r.r_abbrvar = xstrdup(fields[RF_ABBRVAR]); if (max_abbrvar_len < strlen(r.r_abbrvar)) max_abbrvar_len = strlen(r.r_abbrvar); rules = growalloc(rules, sizeof *rules, nrules, &nrules_alloc); @@ -1990,7 +2021,8 @@ inzsub(char **fields, int nfields, bool iscont) z.z_filenum = filenum; z.z_linenum = linenum; z.z_stdoff = gethms(fields[i_stdoff], _("invalid UT offset")); - if ((cp = strchr(fields[i_format], '%')) != 0) { + cp = strchr(fields[i_format], '%'); + if (cp) { if ((*++cp != 's' && *cp != 'z') || strchr(cp, '%') || strchr(fields[i_format], '/')) { error(_("invalid abbreviation format")); @@ -2028,9 +2060,9 @@ inzsub(char **fields, int nfields, bool iscont) return false; } } - z.z_name = iscont ? NULL : estrdup(fields[ZF_NAME]); - z.z_rule = estrdup(fields[i_rule]); - z.z_format = cp1 = estrdup(fields[i_format]); + z.z_name = iscont ? NULL : xstrdup(fields[ZF_NAME]); + z.z_rule = xstrdup(fields[i_rule]); + z.z_format = cp1 = xstrdup(fields[i_format]); if (z.z_format_specifier == 'z') { cp1[cp - fields[i_format]] = 's'; if (noise) @@ -2173,8 +2205,8 @@ inlink(char **fields, int nfields) return; l.l_filenum = filenum; l.l_linenum = linenum; - l.l_target = estrdup(fields[LF_TARGET]); - l.l_linkname = estrdup(fields[LF_LINKNAME]); + l.l_target = xstrdup(fields[LF_TARGET]); + l.l_linkname = xstrdup(fields[LF_LINKNAME]); links = growalloc(links, sizeof *links, nlinks, &nlinks_alloc); links[nlinks++] = l; } @@ -2197,7 +2229,7 @@ rulesub(struct rule *rp, const char *loyearp, const char *hiyearp, rp->r_month = lp->l_value; rp->r_todisstd = false; rp->r_todisut = false; - dp = estrdup(timep); + dp = xstrdup(timep); if (*dp != '\0') { ep = dp + strlen(dp) - 1; switch (lowerit(*ep)) { @@ -2272,19 +2304,23 @@ rulesub(struct rule *rp, const char *loyearp, const char *hiyearp, ** Sun<=20 ** Sun>=7 */ - dp = estrdup(dayp); + dp = xstrdup(dayp); if ((lp = byword(dp, lasts)) != NULL) { rp->r_dycode = DC_DOWLEQ; rp->r_wday = lp->l_value; rp->r_dayofmonth = len_months[1][rp->r_month]; } else { - if ((ep = strchr(dp, '<')) != 0) - rp->r_dycode = DC_DOWLEQ; - else if ((ep = strchr(dp, '>')) != 0) - rp->r_dycode = DC_DOWGEQ; + ep = strchr(dp, '<'); + if (ep) + rp->r_dycode = DC_DOWLEQ; else { + ep = strchr(dp, '>'); + if (ep) + rp->r_dycode = DC_DOWGEQ; + else { ep = dp; rp->r_dycode = DC_DOM; + } } if (rp->r_dycode != DC_DOM) { *ep++ = 0; @@ -2427,7 +2463,7 @@ writezone(const char *const name, const char *const string, char version, /* Allocate the ATS and TYPES arrays via a single malloc, as this is a bit faster. Do not malloc(0) if !timecnt, as that might return NULL even on success. */ - zic_t *ats = emalloc(align_to(size_product(timecnt + !timecnt, + zic_t *ats = xmalloc(align_to(size_product(timecnt + !timecnt, sizeof *ats + 1), alignof(zic_t))); void *typesptr = ats + timecnt; @@ -2802,7 +2838,7 @@ writezone(const char *const name, const char *const string, char version, if (thisleapexpiry) { /* Append a no-op leap correction indicating when the leap second table expires. Although this does not conform to - Internet RFC 8536, most clients seem to accept this and + Internet RFC 9636, most clients seem to accept this and the plan is to amend the RFC to allow this in version 4 TZif files. */ puttzcodepass(leapexpires, fp, pass); @@ -3059,7 +3095,7 @@ stringzone(char *result, struct zone const *zpfirst, ptrdiff_t zonecount) result[0] = '\0'; - /* Internet RFC 8536 section 5.1 says to use an empty TZ string if + /* Internet RFC 9636 section 6.1 says to use an empty TZ string if future timestamps are truncated. */ if (hi_time < max_time) return -1; @@ -3187,9 +3223,9 @@ outzone(const struct zone *zpfirst, ptrdiff_t zonecount) max_abbr_len = 2 + max_format_len + max_abbrvar_len; max_envvar_len = 2 * max_abbr_len + 5 * 9; - startbuf = emalloc(max_abbr_len + 1); - ab = emalloc(max_abbr_len + 1); - envvar = emalloc(max_envvar_len + 1); + startbuf = xmalloc(max_abbr_len + 1); + ab = xmalloc(max_abbr_len + 1); + envvar = xmalloc(max_envvar_len + 1); INITIALIZE(untiltime); INITIALIZE(starttime); /* @@ -3972,7 +4008,7 @@ mkdirs(char const *argname, bool ancestors) if (Dflag) return; - char *name = estrdup(argname); + char *name = xstrdup(argname); char *cp = name; /* On MS-Windows systems, do not worry about drive letters or |