diff options
-rw-r--r-- | Makefile.am | 8 | ||||
-rw-r--r-- | Makefile.in | 184 | ||||
-rwxr-xr-x | configure | 27 | ||||
-rw-r--r-- | configure.ac | 4 | ||||
-rw-r--r-- | src/base/arm_instruction_set_select.h | 79 | ||||
-rw-r--r-- | src/base/cycleclock.h | 35 | ||||
-rw-r--r-- | src/base/logging.h | 11 | ||||
-rw-r--r-- | src/base/low_level_alloc.cc | 4 | ||||
-rw-r--r-- | src/base/spinlock_linux-inl.h | 5 | ||||
-rw-r--r-- | src/base/stl_allocator.h | 1 | ||||
-rw-r--r-- | src/base/sysinfo.cc | 8 | ||||
-rw-r--r-- | src/config.h.in | 6 | ||||
-rw-r--r-- | src/debugallocation.cc | 656 | ||||
-rw-r--r-- | src/google/tcmalloc.h.in | 2 | ||||
-rw-r--r-- | src/heap-checker.cc | 18 | ||||
-rw-r--r-- | src/internal_logging.cc | 7 | ||||
-rw-r--r-- | src/raw_printer.cc | 2 | ||||
-rw-r--r-- | src/tcmalloc.cc | 42 | ||||
-rw-r--r-- | src/tests/debugallocation_test.cc | 2 | ||||
-rw-r--r-- | src/tests/heap-checker_unittest.cc | 7 | ||||
-rw-r--r-- | src/tests/memalign_unittest.cc | 9 | ||||
-rwxr-xr-x | src/tests/sampler_test.cc | 2 | ||||
-rw-r--r-- | src/windows/config.h | 4 | ||||
-rw-r--r-- | src/windows/google/tcmalloc.h.in (renamed from src/windows/google/tcmalloc.h) | 13 | ||||
-rw-r--r-- | src/windows/port.cc | 45 | ||||
-rw-r--r-- | src/windows/port.h | 352 |
26 files changed, 921 insertions, 612 deletions
diff --git a/Makefile.am b/Makefile.am index e18e9ae..a8a2527 100644 --- a/Makefile.am +++ b/Makefile.am @@ -23,7 +23,8 @@ AM_CXXFLAGS = # builtins now in any case, but it's best to be explicit in case that # changes one day. gcc ignores functions it doesn't understand. if GCC -AM_CXXFLAGS += -Wall -Wwrite-strings -Woverloaded-virtual -Wno-sign-compare \ +AM_CXXFLAGS += -Wall -Wwrite-strings -Woverloaded-virtual \ + -Wno-sign-compare -Wno-unused-result \ -fno-builtin-malloc -fno-builtin-free -fno-builtin-realloc \ -fno-builtin-calloc -fno-builtin-cfree \ -fno-builtin-memalign -fno-builtin-posix_memalign \ @@ -162,6 +163,7 @@ SYSINFO_INCLUDES = src/base/sysinfo.h \ src/base/logging.h \ src/base/commandlineflags.h \ src/base/cycleclock.h \ + src/base/arm_instruction_set_select.h \ src/base/basictypes.h noinst_LTLIBRARIES += libsysinfo.la libsysinfo_la_SOURCES = src/base/sysinfo.cc \ @@ -716,6 +718,9 @@ realloc_debug_unittest_CXXFLAGS = $(realloc_unittest_CXXFLAGS) realloc_debug_unittest_LDFLAGS = $(realloc_unittest_LDFLAGS) realloc_debug_unittest_LDADD = libtcmalloc_minimal_debug.la $(PTHREAD_LIBS) +# debugallocation_test checks that we print a proper stacktrace when +# debug-allocs fail, so we can't run it if we don't have stacktrace info. +if WITH_STACK_TRACE TESTS += debugallocation_test.sh$(EXEEXT) debugallocation_test_sh_SOURCES = src/tests/debugallocation_test.sh noinst_SCRIPTS += $(debugallocation_test_sh_SOURCES) @@ -730,6 +735,7 @@ debugallocation_test_SOURCES = src/tests/debugallocation_test.cc debugallocation_test_CXXFLAGS = $(PTHREAD_CFLAGS) $(AM_CXXFLAGS) debugallocation_test_LDFLAGS = $(PTHREAD_CFLAGS) $(TCMALLOC_FLAGS) debugallocation_test_LDADD = libtcmalloc_debug.la $(PTHREAD_LIBS) +endif WITH_STACK_TRACE endif WITH_DEBUGALLOC diff --git a/Makefile.in b/Makefile.in index 693230b..e173564 100644 --- a/Makefile.in +++ b/Makefile.in @@ -51,7 +51,8 @@ host_triplet = @host@ # are supported since gcc 3.1.1). gcc doesn't think most of them are # builtins now in any case, but it's best to be explicit in case that # changes one day. gcc ignores functions it doesn't understand. -@GCC_TRUE@am__append_2 = -Wall -Wwrite-strings -Woverloaded-virtual -Wno-sign-compare \ +@GCC_TRUE@am__append_2 = -Wall -Wwrite-strings -Woverloaded-virtual \ +@GCC_TRUE@ -Wno-sign-compare -Wno-unused-result \ @GCC_TRUE@ -fno-builtin-malloc -fno-builtin-free -fno-builtin-realloc \ @GCC_TRUE@ -fno-builtin-calloc -fno-builtin-cfree \ @GCC_TRUE@ -fno-builtin-memalign -fno-builtin-posix_memalign \ @@ -67,7 +68,7 @@ host_triplet = @host@ @MINGW_TRUE@am__append_5 = -Wl,-u__tcmalloc noinst_PROGRAMS = $(am__EXEEXT_1) $(am__EXEEXT_2) $(am__EXEEXT_3) \ $(am__EXEEXT_4) $(am__EXEEXT_5) $(am__EXEEXT_6) \ - $(am__EXEEXT_7) $(am__EXEEXT_8) $(am__EXEEXT_23) + $(am__EXEEXT_7) $(am__EXEEXT_8) $(am__EXEEXT_24) bin_PROGRAMS = @MINGW_TRUE@am__append_6 = libwindows.la libspinlock.la @@ -128,13 +129,16 @@ bin_PROGRAMS = @WITH_DEBUGALLOC_TRUE@am__append_24 = tcmalloc_minimal_debug_unittest \ @WITH_DEBUGALLOC_TRUE@ malloc_extension_debug_test \ @WITH_DEBUGALLOC_TRUE@ memalign_debug_unittest \ -@WITH_DEBUGALLOC_TRUE@ realloc_debug_unittest \ -@WITH_DEBUGALLOC_TRUE@ debugallocation_test.sh$(EXEEXT) -@WITH_DEBUGALLOC_TRUE@am__append_25 = $(debugallocation_test_sh_SOURCES) +@WITH_DEBUGALLOC_TRUE@ realloc_debug_unittest + +# debugallocation_test checks that we print a proper stacktrace when +# debug-allocs fail, so we can't run it if we don't have stacktrace info. +@WITH_DEBUGALLOC_TRUE@@WITH_STACK_TRACE_TRUE@am__append_25 = debugallocation_test.sh$(EXEEXT) +@WITH_DEBUGALLOC_TRUE@@WITH_STACK_TRACE_TRUE@am__append_26 = $(debugallocation_test_sh_SOURCES) # This is the sub-program used by debugallocation_test.sh -@WITH_DEBUGALLOC_TRUE@am__append_26 = debugallocation_test -@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@am__append_27 = $(SG_TCMALLOC_INCLUDES) +@WITH_DEBUGALLOC_TRUE@@WITH_STACK_TRACE_TRUE@am__append_27 = debugallocation_test +@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@am__append_28 = $(SG_TCMALLOC_INCLUDES) ### Making the library @@ -142,12 +146,12 @@ bin_PROGRAMS = # for all files in this library -- except tcmalloc.cc which needs them # to fulfill its API. Automake doesn't allow per-file CXXFLAGS, so we need # to separate into two libraries. -@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@am__append_28 = libtcmalloc_internal.la -@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@am__append_29 = libtcmalloc.la -@WITH_HEAP_CHECKER_TRUE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@am__append_30 = $(HEAP_CHECKER_SOURCES) -@WITH_HEAP_CHECKER_FALSE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@am__append_31 = -DNO_HEAP_CHECK +@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@am__append_29 = libtcmalloc_internal.la +@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@am__append_30 = libtcmalloc.la +@WITH_HEAP_CHECKER_TRUE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@am__append_31 = $(HEAP_CHECKER_SOURCES) @WITH_HEAP_CHECKER_FALSE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@am__append_32 = -DNO_HEAP_CHECK -@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@am__append_33 = libtcmalloc.la +@WITH_HEAP_CHECKER_FALSE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@am__append_33 = -DNO_HEAP_CHECK +@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@am__append_34 = libtcmalloc.la ### Unittests @@ -155,7 +159,7 @@ bin_PROGRAMS = # tcmalloc_minimal. (One would never do this on purpose, but perhaps # by accident...) When we can compile libprofiler, we also link it in # to make sure that works too. -@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@am__append_34 = tcmalloc_unittest \ +@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@am__append_35 = tcmalloc_unittest \ @WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ tcmalloc_both_unittest \ @WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ tcmalloc_large_unittest \ @WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ raw_printer_test \ @@ -166,74 +170,74 @@ bin_PROGRAMS = # on, which it's not by default. Use the "standard" value of 2^19. # These unittests often need to run binaries. They're in the current dir -@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@am__append_35 = TCMALLOC_SAMPLE_PARAMETER=524288 \ +@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@am__append_36 = TCMALLOC_SAMPLE_PARAMETER=524288 \ @WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ BINDIR=. \ @WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ TMPDIR=/tmp/perftools -@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@am__append_36 = vsprojects/sampler_test/sampler_test.vcproj -@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@am__append_37 = $(sampling_test_sh_SOURCES) +@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@am__append_37 = vsprojects/sampler_test/sampler_test.vcproj +@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@am__append_38 = $(sampling_test_sh_SOURCES) # This is the sub-program used by sampling_test.sh # The -g is so pprof can get symbol information. -@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@am__append_38 = sampling_test -@WITH_HEAP_PROFILER_TRUE@am__append_39 = heap-profiler_unittest.sh$(EXEEXT) -@WITH_HEAP_PROFILER_TRUE@am__append_40 = $(heap_profiler_unittest_sh_SOURCES) +@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@am__append_39 = sampling_test +@WITH_HEAP_PROFILER_TRUE@am__append_40 = heap-profiler_unittest.sh$(EXEEXT) +@WITH_HEAP_PROFILER_TRUE@am__append_41 = $(heap_profiler_unittest_sh_SOURCES) # These are sub-programs used by heap-profiler_unittest.sh -@WITH_HEAP_PROFILER_TRUE@am__append_41 = heap-profiler_unittest -@WITH_HEAP_CHECKER_TRUE@am__append_42 = \ +@WITH_HEAP_PROFILER_TRUE@am__append_42 = heap-profiler_unittest +@WITH_HEAP_CHECKER_TRUE@am__append_43 = \ @WITH_HEAP_CHECKER_TRUE@ heap-checker_unittest.sh$(EXEEXT) \ @WITH_HEAP_CHECKER_TRUE@ heap-checker-death_unittest.sh$(EXEEXT) -@WITH_HEAP_CHECKER_TRUE@am__append_43 = \ +@WITH_HEAP_CHECKER_TRUE@am__append_44 = \ @WITH_HEAP_CHECKER_TRUE@ $(heap_checker_unittest_sh_SOURCES) \ @WITH_HEAP_CHECKER_TRUE@ $(top_srcdir)/$(heap_checker_death_unittest_sh_SOURCES) # These are sub-programs used by heap-checker_unittest.sh -@WITH_HEAP_CHECKER_TRUE@am__append_44 = heap-checker_unittest +@WITH_HEAP_CHECKER_TRUE@am__append_45 = heap-checker_unittest ### Documentation (above and beyond tcmalloc_minimal documentation) -@WITH_HEAP_PROFILER_TRUE@am__append_45 = doc/heapprofile.html doc/heap-example1.png -@WITH_HEAP_CHECKER_TRUE@am__append_46 = doc/heap_checker.html +@WITH_HEAP_PROFILER_TRUE@am__append_46 = doc/heapprofile.html doc/heap-example1.png +@WITH_HEAP_CHECKER_TRUE@am__append_47 = doc/heap_checker.html ### ------- tcmalloc with debugallocation -@WITH_DEBUGALLOC_TRUE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@am__append_47 = libtcmalloc_debug.la @WITH_DEBUGALLOC_TRUE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@am__append_48 = libtcmalloc_debug.la +@WITH_DEBUGALLOC_TRUE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@am__append_49 = libtcmalloc_debug.la ### Unittests -@WITH_DEBUGALLOC_TRUE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@am__append_49 = tcmalloc_debug_unittest \ +@WITH_DEBUGALLOC_TRUE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@am__append_50 = tcmalloc_debug_unittest \ @WITH_DEBUGALLOC_TRUE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ sampler_debug_test \ @WITH_DEBUGALLOC_TRUE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ sampling_debug_test.sh$(EXEEXT) # This is the sub-program using by sampling_debug_test.sh # The -g is so pprof can get symbol information. -@WITH_DEBUGALLOC_TRUE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@am__append_50 = sampling_debug_test -@WITH_DEBUGALLOC_TRUE@@WITH_HEAP_PROFILER_TRUE@am__append_51 = heap-profiler_debug_unittest.sh$(EXEEXT) +@WITH_DEBUGALLOC_TRUE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@am__append_51 = sampling_debug_test +@WITH_DEBUGALLOC_TRUE@@WITH_HEAP_PROFILER_TRUE@am__append_52 = heap-profiler_debug_unittest.sh$(EXEEXT) # These are sub-programs used by heap-profiler_debug_unittest.sh -@WITH_DEBUGALLOC_TRUE@@WITH_HEAP_PROFILER_TRUE@am__append_52 = heap-profiler_debug_unittest -@WITH_DEBUGALLOC_TRUE@@WITH_HEAP_CHECKER_TRUE@am__append_53 = heap-checker_debug_unittest.sh$(EXEEXT) +@WITH_DEBUGALLOC_TRUE@@WITH_HEAP_PROFILER_TRUE@am__append_53 = heap-profiler_debug_unittest +@WITH_DEBUGALLOC_TRUE@@WITH_HEAP_CHECKER_TRUE@am__append_54 = heap-checker_debug_unittest.sh$(EXEEXT) # These are sub-programs used by heap-checker_debug_unittest.sh -@WITH_DEBUGALLOC_TRUE@@WITH_HEAP_CHECKER_TRUE@am__append_54 = heap-checker_debug_unittest -@WITH_CPU_PROFILER_TRUE@am__append_55 = $(SG_CPU_PROFILER_INCLUDES) +@WITH_DEBUGALLOC_TRUE@@WITH_HEAP_CHECKER_TRUE@am__append_55 = heap-checker_debug_unittest +@WITH_CPU_PROFILER_TRUE@am__append_56 = $(SG_CPU_PROFILER_INCLUDES) ### Making the library -@WITH_CPU_PROFILER_TRUE@am__append_56 = libprofiler.la +@WITH_CPU_PROFILER_TRUE@am__append_57 = libprofiler.la ### Unittests -@WITH_CPU_PROFILER_TRUE@am__append_57 = getpc_test \ +@WITH_CPU_PROFILER_TRUE@am__append_58 = getpc_test \ @WITH_CPU_PROFILER_TRUE@ profiledata_unittest \ @WITH_CPU_PROFILER_TRUE@ profile_handler_unittest \ @WITH_CPU_PROFILER_TRUE@ profiler_unittest.sh$(EXEEXT) -@WITH_CPU_PROFILER_TRUE@am__append_58 = $(profiler_unittest_sh_SOURCES) +@WITH_CPU_PROFILER_TRUE@am__append_59 = $(profiler_unittest_sh_SOURCES) # These are sub-programs used by profiler_unittest.sh -@WITH_CPU_PROFILER_TRUE@am__append_59 = profiler1_unittest profiler2_unittest profiler3_unittest \ +@WITH_CPU_PROFILER_TRUE@am__append_60 = profiler1_unittest profiler2_unittest profiler3_unittest \ @WITH_CPU_PROFILER_TRUE@ profiler4_unittest @WITH_CPU_PROFILER_FALSE@profiler2_unittest_DEPENDENCIES = ### Documentation -@WITH_CPU_PROFILER_TRUE@am__append_60 = doc/cpuprofile.html \ +@WITH_CPU_PROFILER_TRUE@am__append_61 = doc/cpuprofile.html \ @WITH_CPU_PROFILER_TRUE@ doc/cpuprofile-fileformat.html \ @WITH_CPU_PROFILER_TRUE@ doc/pprof-test-big.gif \ @WITH_CPU_PROFILER_TRUE@ doc/pprof-test.gif \ @@ -248,14 +252,15 @@ bin_PROGRAMS = # works fine for .so files, it does not for .a files. The easiest way # around this -- and I've tried a bunch of the hard ways -- is to just # to create another set of libraries that has both functionality in it. -@WITH_CPU_PROFILER_TRUE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@am__append_61 = libtcmalloc_and_profiler.la -@WITH_CPU_PROFILER_TRUE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@am__append_62 = tcmalloc_and_profiler_unittest -@WITH_CPU_PROFILER_TRUE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@am__append_63 = libtcmalloc_and_profiler.la +@WITH_CPU_PROFILER_TRUE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@am__append_62 = libtcmalloc_and_profiler.la +@WITH_CPU_PROFILER_TRUE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@am__append_63 = tcmalloc_and_profiler_unittest +@WITH_CPU_PROFILER_TRUE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@am__append_64 = libtcmalloc_and_profiler.la DIST_COMMON = README $(am__configure_deps) $(am__dist_doc_DATA_DIST) \ $(am__googleinclude_HEADERS_DIST) $(dist_man_MANS) \ $(noinst_HEADERS) $(srcdir)/Makefile.am $(srcdir)/Makefile.in \ $(top_srcdir)/configure $(top_srcdir)/src/config.h.in \ - $(top_srcdir)/src/google/tcmalloc.h.in AUTHORS COPYING \ + $(top_srcdir)/src/google/tcmalloc.h.in \ + $(top_srcdir)/src/windows/google/tcmalloc.h.in AUTHORS COPYING \ ChangeLog INSTALL NEWS TODO compile config.guess config.sub \ depcomp install-sh ltmain.sh missing mkinstalldirs subdir = . @@ -277,7 +282,8 @@ am__CONFIG_DISTCLEAN_FILES = config.status config.cache config.log \ configure.lineno configure.status.lineno mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs CONFIG_HEADER = $(top_builddir)/src/config.h -CONFIG_CLEAN_FILES = src/google/tcmalloc.h +CONFIG_CLEAN_FILES = src/google/tcmalloc.h \ + src/windows/google/tcmalloc.h am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ @@ -710,7 +716,7 @@ am__libwindows_la_SOURCES_DIST = src/windows/port.h \ libwindows_la_OBJECTS = $(am_libwindows_la_OBJECTS) @MINGW_TRUE@am_libwindows_la_rpath = binPROGRAMS_INSTALL = $(INSTALL_PROGRAM) -@WITH_DEBUGALLOC_TRUE@am__EXEEXT_1 = debugallocation_test$(EXEEXT) +@WITH_DEBUGALLOC_TRUE@@WITH_STACK_TRACE_TRUE@am__EXEEXT_1 = debugallocation_test$(EXEEXT) @WITH_HEAP_PROFILER_OR_CHECKER_TRUE@am__EXEEXT_2 = \ @WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ sampling_test$(EXEEXT) @WITH_HEAP_PROFILER_TRUE@am__EXEEXT_3 = \ @@ -731,30 +737,30 @@ binPROGRAMS_INSTALL = $(INSTALL_PROGRAM) @WITH_DEBUGALLOC_TRUE@am__EXEEXT_14 = tcmalloc_minimal_debug_unittest$(EXEEXT) \ @WITH_DEBUGALLOC_TRUE@ malloc_extension_debug_test$(EXEEXT) \ @WITH_DEBUGALLOC_TRUE@ memalign_debug_unittest$(EXEEXT) \ -@WITH_DEBUGALLOC_TRUE@ realloc_debug_unittest$(EXEEXT) \ -@WITH_DEBUGALLOC_TRUE@ debugallocation_test.sh$(EXEEXT) -@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@am__EXEEXT_15 = tcmalloc_unittest$(EXEEXT) \ +@WITH_DEBUGALLOC_TRUE@ realloc_debug_unittest$(EXEEXT) +@WITH_DEBUGALLOC_TRUE@@WITH_STACK_TRACE_TRUE@am__EXEEXT_15 = debugallocation_test.sh$(EXEEXT) +@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@am__EXEEXT_16 = tcmalloc_unittest$(EXEEXT) \ @WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ tcmalloc_both_unittest$(EXEEXT) \ @WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ tcmalloc_large_unittest$(EXEEXT) \ @WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ raw_printer_test$(EXEEXT) \ @WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ sampler_test$(EXEEXT) \ @WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ sampling_test.sh$(EXEEXT) -@WITH_HEAP_PROFILER_TRUE@am__EXEEXT_16 = \ +@WITH_HEAP_PROFILER_TRUE@am__EXEEXT_17 = \ @WITH_HEAP_PROFILER_TRUE@ heap-profiler_unittest.sh$(EXEEXT) -@WITH_HEAP_CHECKER_TRUE@am__EXEEXT_17 = \ +@WITH_HEAP_CHECKER_TRUE@am__EXEEXT_18 = \ @WITH_HEAP_CHECKER_TRUE@ heap-checker_unittest.sh$(EXEEXT) \ @WITH_HEAP_CHECKER_TRUE@ heap-checker-death_unittest.sh$(EXEEXT) -@WITH_DEBUGALLOC_TRUE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@am__EXEEXT_18 = tcmalloc_debug_unittest$(EXEEXT) \ +@WITH_DEBUGALLOC_TRUE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@am__EXEEXT_19 = tcmalloc_debug_unittest$(EXEEXT) \ @WITH_DEBUGALLOC_TRUE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ sampler_debug_test$(EXEEXT) \ @WITH_DEBUGALLOC_TRUE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ sampling_debug_test.sh$(EXEEXT) -@WITH_DEBUGALLOC_TRUE@@WITH_HEAP_PROFILER_TRUE@am__EXEEXT_19 = heap-profiler_debug_unittest.sh$(EXEEXT) -@WITH_DEBUGALLOC_TRUE@@WITH_HEAP_CHECKER_TRUE@am__EXEEXT_20 = heap-checker_debug_unittest.sh$(EXEEXT) -@WITH_CPU_PROFILER_TRUE@am__EXEEXT_21 = getpc_test$(EXEEXT) \ +@WITH_DEBUGALLOC_TRUE@@WITH_HEAP_PROFILER_TRUE@am__EXEEXT_20 = heap-profiler_debug_unittest.sh$(EXEEXT) +@WITH_DEBUGALLOC_TRUE@@WITH_HEAP_CHECKER_TRUE@am__EXEEXT_21 = heap-checker_debug_unittest.sh$(EXEEXT) +@WITH_CPU_PROFILER_TRUE@am__EXEEXT_22 = getpc_test$(EXEEXT) \ @WITH_CPU_PROFILER_TRUE@ profiledata_unittest$(EXEEXT) \ @WITH_CPU_PROFILER_TRUE@ profile_handler_unittest$(EXEEXT) \ @WITH_CPU_PROFILER_TRUE@ profiler_unittest.sh$(EXEEXT) -@WITH_CPU_PROFILER_TRUE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@am__EXEEXT_22 = tcmalloc_and_profiler_unittest$(EXEEXT) -am__EXEEXT_23 = low_level_alloc_unittest$(EXEEXT) \ +@WITH_CPU_PROFILER_TRUE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@am__EXEEXT_23 = tcmalloc_and_profiler_unittest$(EXEEXT) +am__EXEEXT_24 = low_level_alloc_unittest$(EXEEXT) \ atomicops_unittest$(EXEEXT) $(am__EXEEXT_9) \ tcmalloc_minimal_unittest$(EXEEXT) \ tcmalloc_minimal_large_unittest$(EXEEXT) $(am__EXEEXT_10) \ @@ -767,7 +773,7 @@ am__EXEEXT_23 = low_level_alloc_unittest$(EXEEXT) \ thread_dealloc_unittest$(EXEEXT) $(am__EXEEXT_14) \ $(am__EXEEXT_15) $(am__EXEEXT_16) $(am__EXEEXT_17) \ $(am__EXEEXT_18) $(am__EXEEXT_19) $(am__EXEEXT_20) \ - $(am__EXEEXT_21) $(am__EXEEXT_22) + $(am__EXEEXT_21) $(am__EXEEXT_22) $(am__EXEEXT_23) PROGRAMS = $(bin_PROGRAMS) $(noinst_PROGRAMS) am__addressmap_unittest_SOURCES_DIST = \ src/tests/addressmap_unittest.cc src/addressmap-inl.h \ @@ -787,11 +793,10 @@ atomicops_unittest_OBJECTS = $(am_atomicops_unittest_OBJECTS) atomicops_unittest_DEPENDENCIES = $(am__DEPENDENCIES_2) am__debugallocation_test_SOURCES_DIST = \ src/tests/debugallocation_test.cc -@WITH_DEBUGALLOC_TRUE@am_debugallocation_test_OBJECTS = debugallocation_test-debugallocation_test.$(OBJEXT) +@WITH_DEBUGALLOC_TRUE@@WITH_STACK_TRACE_TRUE@am_debugallocation_test_OBJECTS = debugallocation_test-debugallocation_test.$(OBJEXT) debugallocation_test_OBJECTS = $(am_debugallocation_test_OBJECTS) -@WITH_DEBUGALLOC_TRUE@debugallocation_test_DEPENDENCIES = \ -@WITH_DEBUGALLOC_TRUE@ libtcmalloc_debug.la \ -@WITH_DEBUGALLOC_TRUE@ $(am__DEPENDENCIES_1) +@WITH_DEBUGALLOC_TRUE@@WITH_STACK_TRACE_TRUE@debugallocation_test_DEPENDENCIES = libtcmalloc_debug.la \ +@WITH_DEBUGALLOC_TRUE@@WITH_STACK_TRACE_TRUE@ $(am__DEPENDENCIES_1) am__debugallocation_test_sh_SOURCES_DIST = \ src/tests/debugallocation_test.sh am_debugallocation_test_sh_OBJECTS = @@ -1631,14 +1636,14 @@ TCMALLOC_FLAGS = $(am__append_5) @HAVE_OBJCOPY_WEAKEN_TRUE@ -W __ZdlPv -W __ZdaPv LIBS_TO_WEAKEN = libtcmalloc_minimal.la $(am__append_23) \ - $(am__append_33) $(am__append_48) $(am__append_63) + $(am__append_34) $(am__append_49) $(am__append_64) googleincludedir = $(includedir)/google # The .h files you want to install (that is, .h files that people # who install this package can include in their own applications.) # We'll add to this later, on a library-by-library basis googleinclude_HEADERS = $(am__append_9) \ - $(SG_TCMALLOC_MINIMAL_INCLUDES) $(am__append_27) \ - $(am__append_55) + $(SG_TCMALLOC_MINIMAL_INCLUDES) $(am__append_28) \ + $(am__append_56) # tcmalloc.h is a special case, because it's a .h.in file nodist_googleinclude_HEADERS = src/google/tcmalloc.h noinst_HEADERS = src/google/tcmalloc.h.in @@ -1680,13 +1685,13 @@ dist_doc_DATA = AUTHORS COPYING ChangeLog INSTALL NEWS README \ doc/tcmalloc-opspersec.vs.size.5.threads.png \ doc/tcmalloc-opspersec.vs.size.8.threads.png doc/overview.dot \ doc/pageheap.dot doc/spanmap.dot doc/threadheap.dot \ - $(am__append_45) $(am__append_46) $(am__append_60) + $(am__append_46) $(am__append_47) $(am__append_61) # The libraries (.so's) you want to install # We'll add to this later, on a library-by-library basis lib_LTLIBRARIES = libtcmalloc_minimal.la $(am__append_22) \ - $(am__append_29) $(am__append_47) $(am__append_56) \ - $(am__append_61) + $(am__append_30) $(am__append_48) $(am__append_57) \ + $(am__append_62) # This is for 'convenience libraries' -- basically just a container for sources ### Making the library @@ -1697,7 +1702,7 @@ lib_LTLIBRARIES = libtcmalloc_minimal.la $(am__append_22) \ # to separate into two libraries. noinst_LTLIBRARIES = liblogging.la libsysinfo.la $(am__append_6) \ $(am__append_8) $(am__append_10) \ - libtcmalloc_minimal_internal.la $(am__append_28) + libtcmalloc_minimal_internal.la $(am__append_29) WINDOWS_PROJECTS = google-perftools.sln \ vsprojects/low_level_alloc_unittest/low_level_alloc_unittest.vcproj \ $(am__append_14) \ @@ -1715,7 +1720,7 @@ WINDOWS_PROJECTS = google-perftools.sln \ vsprojects/realloc_unittest/realloc_unittest.vcproj \ vsprojects/stack_trace_table_test/stack_trace_table_test.vcproj \ vsprojects/thread_dealloc_unittest/thread_dealloc_unittest.vcproj \ - $(am__append_36) + $(am__append_37) # unittests you want to run when people type 'make check'. # Note: tests cannot take any arguments! @@ -1741,16 +1746,17 @@ TESTS = low_level_alloc_unittest atomicops_unittest $(am__append_11) \ malloc_extension_test $(am__append_19) $(am__append_21) \ page_heap_test pagemap_unittest realloc_unittest \ stack_trace_table_test thread_dealloc_unittest \ - $(am__append_24) $(am__append_34) $(am__append_39) \ - $(am__append_42) $(am__append_49) $(am__append_51) \ - $(am__append_53) $(am__append_57) $(am__append_62) + $(am__append_24) $(am__append_25) $(am__append_35) \ + $(am__append_40) $(am__append_43) $(am__append_50) \ + $(am__append_52) $(am__append_54) $(am__append_58) \ + $(am__append_63) # TESTS_ENVIRONMENT sets environment variables for when you run unittest. # We always get "srcdir" set for free. # We'll add to this later, on a library-by-library basis. -TESTS_ENVIRONMENT = $(am__append_13) $(am__append_35) +TESTS_ENVIRONMENT = $(am__append_13) $(am__append_36) # All script tests should be added here -noinst_SCRIPTS = $(am__append_16) $(am__append_25) $(am__append_37) \ - $(am__append_40) $(am__append_43) $(am__append_58) +noinst_SCRIPTS = $(am__append_16) $(am__append_26) $(am__append_38) \ + $(am__append_41) $(am__append_44) $(am__append_59) # This is my own var, used for extra libraries I make that I need installed EXTRA_INSTALL = @@ -1772,6 +1778,7 @@ SYSINFO_INCLUDES = src/base/sysinfo.h \ src/base/logging.h \ src/base/commandlineflags.h \ src/base/cycleclock.h \ + src/base/arm_instruction_set_select.h \ src/base/basictypes.h libsysinfo_la_SOURCES = src/base/sysinfo.cc \ @@ -2131,11 +2138,11 @@ thread_dealloc_unittest_LDADD = $(LIBTCMALLOC_MINIMAL) $(PTHREAD_LIBS) @WITH_DEBUGALLOC_TRUE@realloc_debug_unittest_CXXFLAGS = $(realloc_unittest_CXXFLAGS) @WITH_DEBUGALLOC_TRUE@realloc_debug_unittest_LDFLAGS = $(realloc_unittest_LDFLAGS) @WITH_DEBUGALLOC_TRUE@realloc_debug_unittest_LDADD = libtcmalloc_minimal_debug.la $(PTHREAD_LIBS) -@WITH_DEBUGALLOC_TRUE@debugallocation_test_sh_SOURCES = src/tests/debugallocation_test.sh -@WITH_DEBUGALLOC_TRUE@debugallocation_test_SOURCES = src/tests/debugallocation_test.cc -@WITH_DEBUGALLOC_TRUE@debugallocation_test_CXXFLAGS = $(PTHREAD_CFLAGS) $(AM_CXXFLAGS) -@WITH_DEBUGALLOC_TRUE@debugallocation_test_LDFLAGS = $(PTHREAD_CFLAGS) $(TCMALLOC_FLAGS) -@WITH_DEBUGALLOC_TRUE@debugallocation_test_LDADD = libtcmalloc_debug.la $(PTHREAD_LIBS) +@WITH_DEBUGALLOC_TRUE@@WITH_STACK_TRACE_TRUE@debugallocation_test_sh_SOURCES = src/tests/debugallocation_test.sh +@WITH_DEBUGALLOC_TRUE@@WITH_STACK_TRACE_TRUE@debugallocation_test_SOURCES = src/tests/debugallocation_test.cc +@WITH_DEBUGALLOC_TRUE@@WITH_STACK_TRACE_TRUE@debugallocation_test_CXXFLAGS = $(PTHREAD_CFLAGS) $(AM_CXXFLAGS) +@WITH_DEBUGALLOC_TRUE@@WITH_STACK_TRACE_TRUE@debugallocation_test_LDFLAGS = $(PTHREAD_CFLAGS) $(TCMALLOC_FLAGS) +@WITH_DEBUGALLOC_TRUE@@WITH_STACK_TRACE_TRUE@debugallocation_test_LDADD = libtcmalloc_debug.la $(PTHREAD_LIBS) ### ------- tcmalloc (thread-caching malloc + heap profiler + heap checker) @@ -2170,17 +2177,17 @@ thread_dealloc_unittest_LDADD = $(LIBTCMALLOC_MINIMAL) $(PTHREAD_LIBS) @WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ $(PTHREAD_CFLAGS) -DNDEBUG \ @WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ $(AM_CXXFLAGS) \ @WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ $(NO_EXCEPTIONS) \ -@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ $(am__append_31) +@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ $(am__append_32) @WITH_HEAP_PROFILER_OR_CHECKER_TRUE@libtcmalloc_internal_la_LDFLAGS = $(PTHREAD_CFLAGS) @WITH_HEAP_PROFILER_OR_CHECKER_TRUE@libtcmalloc_internal_la_LIBADD = libstacktrace.la $(PTHREAD_LIBS) @WITH_HEAP_PROFILER_OR_CHECKER_TRUE@libtcmalloc_la_SOURCES = \ @WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ $(TCMALLOC_CC) \ @WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ $(TCMALLOC_INCLUDES) \ -@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ $(am__append_30) +@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ $(am__append_31) @WITH_HEAP_PROFILER_OR_CHECKER_TRUE@libtcmalloc_la_CXXFLAGS = \ @WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ $(PTHREAD_CFLAGS) -DNDEBUG \ @WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ $(AM_CXXFLAGS) \ -@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ $(am__append_32) +@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ $(am__append_33) @WITH_HEAP_PROFILER_OR_CHECKER_TRUE@libtcmalloc_la_LDFLAGS = $(PTHREAD_CFLAGS) -version-info @TCMALLOC_SO_VERSION@ @WITH_HEAP_PROFILER_OR_CHECKER_TRUE@libtcmalloc_la_LIBADD = libtcmalloc_internal.la $(PTHREAD_LIBS) @WITH_HEAP_CHECKER_FALSE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@HEAP_CHECKER_SOURCES = @@ -2494,6 +2501,8 @@ distclean-hdr: -rm -f src/config.h src/stamp-h1 src/google/tcmalloc.h: $(top_builddir)/config.status $(top_srcdir)/src/google/tcmalloc.h.in cd $(top_builddir) && $(SHELL) ./config.status $@ +src/windows/google/tcmalloc.h: $(top_builddir)/config.status $(top_srcdir)/src/windows/google/tcmalloc.h.in + cd $(top_builddir) && $(SHELL) ./config.status $@ install-libLTLIBRARIES: $(lib_LTLIBRARIES) @$(NORMAL_INSTALL) test -z "$(libdir)" || $(mkdir_p) "$(DESTDIR)$(libdir)" @@ -2603,6 +2612,9 @@ debugallocation_test$(EXEEXT): $(debugallocation_test_OBJECTS) $(debugallocation @WITH_DEBUGALLOC_FALSE@debugallocation_test.sh$(EXEEXT): $(debugallocation_test_sh_OBJECTS) $(debugallocation_test_sh_DEPENDENCIES) @WITH_DEBUGALLOC_FALSE@ @rm -f debugallocation_test.sh$(EXEEXT) @WITH_DEBUGALLOC_FALSE@ $(LINK) $(debugallocation_test_sh_LDFLAGS) $(debugallocation_test_sh_OBJECTS) $(debugallocation_test_sh_LDADD) $(LIBS) +@WITH_STACK_TRACE_FALSE@debugallocation_test.sh$(EXEEXT): $(debugallocation_test_sh_OBJECTS) $(debugallocation_test_sh_DEPENDENCIES) +@WITH_STACK_TRACE_FALSE@ @rm -f debugallocation_test.sh$(EXEEXT) +@WITH_STACK_TRACE_FALSE@ $(LINK) $(debugallocation_test_sh_LDFLAGS) $(debugallocation_test_sh_OBJECTS) $(debugallocation_test_sh_LDADD) $(LIBS) frag_unittest$(EXEEXT): $(frag_unittest_OBJECTS) $(frag_unittest_DEPENDENCIES) @rm -f frag_unittest$(EXEEXT) $(CXXLINK) $(frag_unittest_LDFLAGS) $(frag_unittest_OBJECTS) $(frag_unittest_LDADD) $(LIBS) @@ -4827,10 +4839,10 @@ uninstall-man: uninstall-man1 @ENABLE_STATIC_FALSE@@MINGW_FALSE@ low_level_alloc_unittest @ENABLE_STATIC_FALSE@@MINGW_FALSE@ rm -f $@ @ENABLE_STATIC_FALSE@@MINGW_FALSE@ cp -p $(top_srcdir)/$(maybe_threads_unittest_sh_SOURCES) $@ -@WITH_DEBUGALLOC_TRUE@debugallocation_test.sh$(EXEEXT): $(top_srcdir)/$(debugallocation_test_sh_SOURCES) \ -@WITH_DEBUGALLOC_TRUE@ debugallocation_test -@WITH_DEBUGALLOC_TRUE@ rm -f $@ -@WITH_DEBUGALLOC_TRUE@ cp -p $(top_srcdir)/$(debugallocation_test_sh_SOURCES) $@ +@WITH_DEBUGALLOC_TRUE@@WITH_STACK_TRACE_TRUE@debugallocation_test.sh$(EXEEXT): $(top_srcdir)/$(debugallocation_test_sh_SOURCES) \ +@WITH_DEBUGALLOC_TRUE@@WITH_STACK_TRACE_TRUE@ debugallocation_test +@WITH_DEBUGALLOC_TRUE@@WITH_STACK_TRACE_TRUE@ rm -f $@ +@WITH_DEBUGALLOC_TRUE@@WITH_STACK_TRACE_TRUE@ cp -p $(top_srcdir)/$(debugallocation_test_sh_SOURCES) $@ @WITH_HEAP_PROFILER_OR_CHECKER_TRUE@sampling_test.sh$(EXEEXT): $(top_srcdir)/$(sampling_test_sh_SOURCES) \ @WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ sampling_test @WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ rm -f $@ @@ -15004,6 +15004,30 @@ fi done # some systems define stuff there, others not +for ac_header in sys/malloc.h +do : + ac_fn_c_check_header_mongrel "$LINENO" "sys/malloc.h" "ac_cv_header_sys_malloc_h" "$ac_includes_default" +if test "x$ac_cv_header_sys_malloc_h" = x""yes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_SYS_MALLOC_H 1 +_ACEOF + +fi + +done + # where some versions of OS X put malloc.h +for ac_header in malloc/malloc.h +do : + ac_fn_c_check_header_mongrel "$LINENO" "malloc/malloc.h" "ac_cv_header_malloc_malloc_h" "$ac_includes_default" +if test "x$ac_cv_header_malloc_malloc_h" = x""yes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_MALLOC_MALLOC_H 1 +_ACEOF + +fi + +done + # another place OS X puts malloc.h (?) for ac_header in glob.h do : ac_fn_c_check_header_mongrel "$LINENO" "glob.h" "ac_cv_header_glob_h" "$ac_includes_default" @@ -16996,7 +17020,7 @@ fi # Write generated configuration file -ac_config_files="$ac_config_files Makefile src/google/tcmalloc.h" +ac_config_files="$ac_config_files Makefile src/google/tcmalloc.h src/windows/google/tcmalloc.h" cat >confcache <<\_ACEOF # This file is a shell script that caches the results of configure @@ -18115,6 +18139,7 @@ do "libtool") CONFIG_COMMANDS="$CONFIG_COMMANDS libtool" ;; "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;; "src/google/tcmalloc.h") CONFIG_FILES="$CONFIG_FILES src/google/tcmalloc.h" ;; + "src/windows/google/tcmalloc.h") CONFIG_FILES="$CONFIG_FILES src/windows/google/tcmalloc.h" ;; *) as_fn_error "invalid argument: \`$ac_config_target'" "$LINENO" 5;; esac diff --git a/configure.ac b/configure.ac index 43ae558..90c015f 100644 --- a/configure.ac +++ b/configure.ac @@ -123,6 +123,8 @@ AC_CHECK_FUNCS(sbrk) # for tcmalloc to get memory AC_CHECK_FUNCS(geteuid) # for turning off services when run as root AC_CHECK_HEADERS(features.h) # for vdso_support.h AC_CHECK_HEADERS(malloc.h) # some systems define stuff there, others not +AC_CHECK_HEADERS(sys/malloc.h) # where some versions of OS X put malloc.h +AC_CHECK_HEADERS(malloc/malloc.h) # another place OS X puts malloc.h (?) AC_CHECK_HEADERS(glob.h) # for heap-profile-table (cleaning up profiles) AC_CHECK_HEADERS(execinfo.h) # for stacktrace? and heapchecker_unittest AC_CHECK_HEADERS(libunwind.h) # for stacktrace @@ -359,5 +361,5 @@ AM_CONDITIONAL(WITH_STACK_TRACE, test "$enable_cpu_profiler" = yes -o \ "$enable_heap_checker" = yes) # Write generated configuration file -AC_CONFIG_FILES([Makefile src/google/tcmalloc.h]) +AC_CONFIG_FILES([Makefile src/google/tcmalloc.h src/windows/google/tcmalloc.h]) AC_OUTPUT diff --git a/src/base/arm_instruction_set_select.h b/src/base/arm_instruction_set_select.h new file mode 100644 index 0000000..a47e6bb --- /dev/null +++ b/src/base/arm_instruction_set_select.h @@ -0,0 +1,79 @@ +// Copyright (c) 2011, 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. +// +// Author: Alexander Levitskiy +// +// Generalizes the plethora of ARM flavors available to an easier to manage set +// Defs reference is at https://wiki.edubuntu.org/ARM/Thumb2PortingHowto + +#ifndef ARM_INSTRUCTION_SET_SELECT_H_ +#define ARM_INSTRUCTION_SET_SELECT_H_ + +#if defined(__ARM_ARCH_7__) || \ + defined(__ARM_ARCH_7R__) || \ + defined(__ARM_ARCH_7A__) +# define ARMV7 1 +#endif + +#if defined(ARMV7) || \ + defined(__ARM_ARCH_6__) || \ + defined(__ARM_ARCH_6J__) || \ + defined(__ARM_ARCH_6K__) || \ + defined(__ARM_ARCH_6Z__) || \ + defined(__ARM_ARCH_6T2__) || \ + defined(__ARM_ARCH_6ZK__) +# define ARMV6 1 +#endif + +#if defined(ARMV6) || \ + defined(__ARM_ARCH_5T__) || \ + defined(__ARM_ARCH_5E__) || \ + defined(__ARM_ARCH_5TE__) || \ + defined(__ARM_ARCH_5TEJ__) +# define ARMV5 1 +#endif + +#if defined(ARMV5) || \ + defined(__ARM_ARCH_4__) || \ + defined(__ARM_ARCH_4T__) +# define ARMV4 1 +#endif + +#if defined(ARMV4) || \ + defined(__ARM_ARCH_3__) || \ + defined(__ARM_ARCH_3M__) +# define ARMV3 1 +#endif + +#if defined(ARMV3) || \ + defined(__ARM_ARCH_2__) +# define ARMV2 1 +#endif + +#endif // ARM_INSTRUCTION_SET_SELECT_H_ diff --git a/src/base/cycleclock.h b/src/base/cycleclock.h index 02cddf3..a5ce138 100644 --- a/src/base/cycleclock.h +++ b/src/base/cycleclock.h @@ -46,11 +46,11 @@ #define GOOGLE_BASE_CYCLECLOCK_H_ #include "base/basictypes.h" // make sure we get the def for int64 +#include "base/arm_instruction_set_select.h" #if defined(__MACH__) && defined(__APPLE__) # include <mach/mach_time.h> -#elif defined(__ARM_ARCH_5T__) || defined(__ARM_ARCH_3__) -# include <sys/time.h> #endif +#include <sys/time.h> // NOTE: only i386 and x86_64 have been well tested. // PPC, sparc, alpha, and ia64 are based on @@ -99,20 +99,29 @@ struct CycleClock { return itc; #elif defined(_MSC_VER) && defined(_M_IX86) _asm rdtsc - -// If none of the above cases trigger, we use a solution based on -// a system call (gettimeofday or similar). We do these in order -// from fastest to slowest. We do not have an '#else' catch-all -// case here that just calls gettimeofday(); that system call is -// slow, and this function is expected to be fast, so we don't want -// to use it without an explicit decision that it's the only way. -#elif defined(__ARM_ARCH_5T__) || defined(__ARM_ARCH_3__) +#elif defined(ARMV3) +#if defined(ARMV6) // V6 is the earliest arch that has a standard cyclecount + uint32 pmccntr; + uint32 pmuseren; + uint32 pmcntenset; + // Read the user mode perf monitor counter access permissions. + asm("mrc p15, 0, %0, c9, c14, 0" : "=r" (pmuseren)); + if (pmuseren & 1) { // Allows reading perfmon counters for user mode code. + asm("mrc p15, 0, %0, c9, c12, 1" : "=r" (pmcntenset)); + if (pmcntenset & 0x80000000ul) { // Is it counting? + asm("mrc p15, 0, %0, c9, c13, 0" : "=r" (pmccntr)); + // The counter is set up to count every 64th cycle + return static_cast<int64>(pmccntr) * 64; // Should optimize to << 6 + } + } +#endif struct timeval tv; gettimeofday(&tv, NULL); - return static_cast<uint64>(tv.tv_sec) * 1000000 + tv.tv_usec; + return static_cast<int64>(tv.tv_sec) * 1000000 + tv.tv_usec; #else - // We could define __alpha here as well, but it only has a 32-bit - // timer (good for like 4 seconds), which isn't very useful. +// The soft failover to a generic implementation is automatic only for ARM. +// For other platforms the developer is expected to make an attempt to create +// a fast implementation and use generic version if nothing better is available. #error You need to define CycleTimer for your O/S and CPU #endif } diff --git a/src/base/logging.h b/src/base/logging.h index 5c3e546..70491ba 100644 --- a/src/base/logging.h +++ b/src/base/logging.h @@ -62,6 +62,13 @@ #define WRITE_TO_STDERR(buf, len) write(STDERR_FILENO, buf, len) #endif +// MSVC and mingw define their own, safe version of vnsprintf (the +// windows one in broken) in port.cc. Everyone else can use the +// version here. We had to give it a unique name for windows. +#ifndef _WIN32 +# define perftools_vsnprintf vsnprintf +#endif + // We log all messages at this log-level and below. // INFO == -1, WARNING == -2, ERROR == -3, FATAL == -4 @@ -191,7 +198,7 @@ inline void LogPrintf(int severity, const char* pat, va_list ap) { // We write directly to the stderr file descriptor and avoid FILE // buffering because that may invoke malloc() char buf[600]; - vsnprintf(buf, sizeof(buf)-1, pat, ap); + perftools_vsnprintf(buf, sizeof(buf)-1, pat, ap); if (buf[0] != '\0' && buf[strlen(buf)-1] != '\n') { assert(strlen(buf)+1 < sizeof(buf)); strcat(buf, "\n"); @@ -233,7 +240,9 @@ inline void LOG_IF(int lvl, bool cond, const char* pat, ...) { // Like other "raw" routines, these functions are best effort, and // thus don't return error codes (except RawOpenForWriting()). #if defined(_WIN32) || defined(__CYGWIN__) || defined(__CYGWIN32__) +#ifndef NOMINMAX #define NOMINMAX // @#!$& windows +#endif #include <windows.h> typedef HANDLE RawFD; const RawFD kIllegalRawFD = INVALID_HANDLE_VALUE; diff --git a/src/base/low_level_alloc.cc b/src/base/low_level_alloc.cc index 8864629..532c594 100644 --- a/src/base/low_level_alloc.cc +++ b/src/base/low_level_alloc.cc @@ -212,7 +212,7 @@ static const intptr_t kMagicAllocated = 0x4c833e95; static const intptr_t kMagicUnallocated = ~kMagicAllocated; namespace { - class ArenaLock { + class SCOPED_LOCKABLE ArenaLock { public: explicit ArenaLock(LowLevelAlloc::Arena *arena) EXCLUSIVE_LOCK_FUNCTION(arena->mu) @@ -233,7 +233,7 @@ namespace { this->arena_->mu.Lock(); } ~ArenaLock() { RAW_CHECK(this->left_, "haven't left Arena region"); } - void Leave() UNLOCK_FUNCTION(arena_->mu) { + void Leave() UNLOCK_FUNCTION() { this->arena_->mu.Unlock(); #if 0 if (this->mask_valid_) { diff --git a/src/base/spinlock_linux-inl.h b/src/base/spinlock_linux-inl.h index 5e571b1..a178dd5 100644 --- a/src/base/spinlock_linux-inl.h +++ b/src/base/spinlock_linux-inl.h @@ -49,8 +49,13 @@ static struct InitModule { int x = 0; // futexes are ints, so we can use them only when // that's the same size as the lockword_ in SpinLock. +#ifdef __arm__ + // ARM linux doesn't support sys_futex1(void*, int, int, struct timespec*); + have_futex = 0; +#else have_futex = (sizeof (Atomic32) == sizeof (int) && sys_futex(&x, FUTEX_WAKE, 1, 0) >= 0); +#endif if (have_futex && sys_futex(&x, FUTEX_WAKE | futex_private_flag, 1, 0) < 0) { futex_private_flag = 0; diff --git a/src/base/stl_allocator.h b/src/base/stl_allocator.h index d9d2983..3152cf9 100644 --- a/src/base/stl_allocator.h +++ b/src/base/stl_allocator.h @@ -40,7 +40,6 @@ #include <stddef.h> // for ptrdiff_t #include <limits> -#include "base/basictypes.h" #include "base/logging.h" // Generic allocator class for STL objects diff --git a/src/base/sysinfo.cc b/src/base/sysinfo.cc index c1e2aef..3e97ac9 100644 --- a/src/base/sysinfo.cc +++ b/src/base/sysinfo.cc @@ -231,6 +231,8 @@ static int64 EstimateCyclesPerSecond(const int estimate_time_ms) { return guess; } +// ReadIntFromFile is only called on linux and cygwin platforms. +#if defined(__linux__) || defined(__CYGWIN__) || defined(__CYGWIN32__) // Helper function for reading an int from a file. Returns true if successful // and the memory location pointed to by value is set to the value read. static bool ReadIntFromFile(const char *file, int *value) { @@ -250,6 +252,7 @@ static bool ReadIntFromFile(const char *file, int *value) { } return ret; } +#endif // WARNING: logging calls back to InitializeSystemInfo() so it must // not invoke any logging code. Also, InitializeSystemInfo() can be @@ -491,7 +494,7 @@ static void ConstructFilename(const char* spec, pid_t pid, char* buf, int buf_size) { CHECK_LT(snprintf(buf, buf_size, spec, - pid ? pid : getpid()), buf_size); + static_cast<int>(pid ? pid : getpid())), buf_size); } #endif @@ -804,7 +807,8 @@ bool ProcMapsIterator::NextExt(uint64 *start, uint64 *end, char **flags, Buffer::kBufSize); } else { CHECK_LT(snprintf(object_path.buf_, Buffer::kBufSize, - "/proc/%d/path/%s", pid_, mapinfo->pr_mapname), + "/proc/%d/path/%s", + static_cast<int>(pid_), mapinfo->pr_mapname), Buffer::kBufSize); } ssize_t len = readlink(object_path.buf_, current_filename_, PATH_MAX); diff --git a/src/config.h.in b/src/config.h.in index 6ee2db0..3b8d6f3 100644 --- a/src/config.h.in +++ b/src/config.h.in @@ -77,6 +77,9 @@ /* Define to 1 if you have the <malloc.h> header file. */ #undef HAVE_MALLOC_H +/* Define to 1 if you have the <malloc/malloc.h> header file. */ +#undef HAVE_MALLOC_MALLOC_H + /* Define to 1 if you have the <memory.h> header file. */ #undef HAVE_MEMORY_H @@ -119,6 +122,9 @@ /* Define to 1 if the system has the type `struct mallinfo'. */ #undef HAVE_STRUCT_MALLINFO +/* Define to 1 if you have the <sys/malloc.h> header file. */ +#undef HAVE_SYS_MALLOC_H + /* Define to 1 if you have the <sys/param.h> header file. */ #undef HAVE_SYS_PARAM_H diff --git a/src/debugallocation.cc b/src/debugallocation.cc index d149ec4..12865eb 100644 --- a/src/debugallocation.cc +++ b/src/debugallocation.cc @@ -31,8 +31,16 @@ // Author: Urs Holzle <opensource@google.com> #include "config.h" -#ifdef HAVE_MALLOC_H -#include <malloc.h> +// We only need malloc.h for struct mallinfo. +#ifdef HAVE_STRUCT_MALLINFO +// Malloc can be in several places on older versions of OS X. +# if defined(HAVE_MALLOC_H) +# include <malloc.h> +# elif defined(HAVE_SYS_MALLOC_H) +# include <sys/malloc.h> +# elif defined(HAVE_MALLOC_MALLOC_H) +# include <malloc/malloc.h> +# endif #endif #include <pthread.h> #include <stdio.h> @@ -127,6 +135,23 @@ static void TracePrintf(int fd, const char *fmt, ...) __attribute__ ((__format__ (__printf__, 2, 3))); // +// Define the malloc/free/mallopt/mallinfo implementations +// we will be working on top of: +#ifdef TCMALLOC_FOR_DEBUGALLOCATION + +// The do_* functions are defined in tcmalloc/tcmalloc.cc, +// which is included before this file +// when TCMALLOC_FOR_DEBUGALLOCATION is defined +#define BASE_MALLOC_NEW(size) cpp_alloc(size, false) +#define BASE_MALLOC do_malloc +#define BASE_FREE do_free +#define BASE_MALLOC_STATS do_malloc_stats +#define BASE_MALLOPT do_mallopt +#define BASE_MALLINFO do_mallinfo +#define BASE_MALLOC_SIZE(ptr) GetSizeWithCallback(ptr, &InvalidGetAllocatedSize) + +#else + // GNU has some weird "weak aliasing" thing that permits us to define our // own malloc(), free(), and realloc() which can use the normal versions of // of themselves by calling __libc_malloc(), __libc_free(), and @@ -141,32 +166,21 @@ extern "C" { #ifdef HAVE_STRUCT_MALLINFO extern struct mallinfo __libc_mallinfo(void); #endif + static void noop_malloc_stats(void) {} } -// Define the malloc/free/mallopt/mallinfo implementations -// we will be working on top of. -// TODO(csilvers): provide debugallocation on top of libc alloc, -// so this #ifdef might sometimes be false. -#ifdef TCMALLOC_FOR_DEBUGALLOCATION - -// The do_* functions are defined in tcmalloc.cc, -// which is included before this file -// when TCMALLOC_FOR_DEBUGALLOCATION is defined. -#define BASE_MALLOC_NEW(size) cpp_alloc(size, false) -#define BASE_MALLOC do_malloc_or_cpp_alloc -#define BASE_FREE do_free -#define BASE_MALLOPT do_mallopt -#define BASE_MALLINFO do_mallinfo - -#else - // We are working on top of standard libc's malloc library -#define BASE_MALLOC_NEW __libc_malloc -#define BASE_MALLOC __libc_malloc -#define BASE_FREE __libc_free -#define BASE_MALLOPT __libc_mallopt -#define BASE_MALLINFO __libc_mallinfo - +#define BASE_MALLOC_NEW __libc_malloc +#define BASE_MALLOC __libc_malloc +#define BASE_FREE __libc_free +#define BASE_MALLOC_STATS noop_malloc_stats +#define BASE_MALLOPT __libc_mallopt +#ifdef HAVE_STRUCT_MALLINFO +#define BASE_MALLINFO __libc_mallinfo +#endif +// This is malloc_size() on OS X, malloc_usable_size() on libc, +// _msize() on windows. Rather than trying to pick, we just bail. +#define BASE_MALLOC_SIZE(ptr) 0 // TODO(csilvers): do better #endif // ========================================================================= // @@ -190,7 +204,7 @@ class FreeQueue { return (q_front_ + 1) % kFreeQueueSize == q_back_; } - void Push(QueueEntry block) { + void Push(const QueueEntry& block) { q_[q_front_] = block; q_front_ = (q_front_ + 1) % kFreeQueueSize; } @@ -982,71 +996,184 @@ static inline void DebugDeallocate(void* ptr, int type) { // ========================================================================= // -// Alloc/free stuff for debug hooks for malloc & friends +// The following functions may be called via MallocExtension::instance() +// for memory verification and statistics. +#ifdef TCMALLOC_FOR_DEBUGALLOCATION +// Inherit from tcmalloc's version +typedef TCMallocImplementation ParentImplementation; +#else +// Inherit from default version +typedef MallocExtension ParentImplementation; +#endif + +class DebugMallocImplementation : public ParentImplementation { + public: + virtual bool GetNumericProperty(const char* name, size_t* value) { + bool result = ParentImplementation::GetNumericProperty(name, value); + if (result && (strcmp(name, "generic.current_allocated_bytes") == 0)) { + // Subtract bytes kept in the free queue + size_t qsize = MallocBlock::FreeQueueSize(); + if (*value >= qsize) { + *value -= qsize; + } + } + return result; + } -// CAVEAT: The code structure below ensures that MallocHook methods are always -// called from the stack frame of the invoked allocation function. -// heap-checker.cc depends on this to start a stack trace from -// the call to the (de)allocation function. + virtual bool VerifyNewMemory(void* p) { + if (p) MallocBlock::FromRawPointer(p)->Check(MallocBlock::kNewType); + return true; + } -// Put all callers of MallocHook::Invoke* in this module into -// ATTRIBUTE_SECTION(google_malloc) section, -// so that MallocHook::GetCallerStackTrace can function accurately: + virtual bool VerifyArrayNewMemory(void* p) { + if (p) MallocBlock::FromRawPointer(p)->Check(MallocBlock::kArrayNewType); + return true; + } -extern "C" { - void* malloc(size_t size) __THROW ATTRIBUTE_SECTION(google_malloc); - void free(void* ptr) __THROW ATTRIBUTE_SECTION(google_malloc); - void* realloc(void* ptr, size_t size) __THROW - ATTRIBUTE_SECTION(google_malloc); - void* calloc(size_t nmemb, size_t size) __THROW - ATTRIBUTE_SECTION(google_malloc); - void cfree(void* ptr) __THROW ATTRIBUTE_SECTION(google_malloc); - - void* memalign(size_t __alignment, size_t __size) __THROW - ATTRIBUTE_SECTION(google_malloc); - int posix_memalign(void** ptr, size_t align, size_t size) __THROW - ATTRIBUTE_SECTION(google_malloc); - void* valloc(size_t __size) __THROW - ATTRIBUTE_SECTION(google_malloc); - void* pvalloc(size_t __size) __THROW - ATTRIBUTE_SECTION(google_malloc); + virtual bool VerifyMallocMemory(void* p) { + if (p) MallocBlock::FromRawPointer(p)->Check(MallocBlock::kMallocType); + return true; + } + + virtual bool VerifyAllMemory() { + return MallocBlock::CheckEverything(); + } + + virtual bool MallocMemoryStats(int* blocks, size_t* total, + int histogram[kMallocHistogramSize]) { + return MallocBlock::MemoryStats(blocks, total, histogram); + } + + virtual size_t GetAllocatedSize(void* p) { + if (p) { + return MallocBlock::FromRawPointer(p)->data_size(); + } + return 0; + } + virtual size_t GetEstimatedAllocatedSize(size_t size) { + return size; + } + + virtual void GetFreeListSizes(vector<MallocExtension::FreeListInfo>* v) { + static const char* kDebugFreeQueue = "debug.free_queue"; + + ParentImplementation::GetFreeListSizes(v); + + MallocExtension::FreeListInfo i; + i.type = kDebugFreeQueue; + i.min_object_size = 0; + i.max_object_size = numeric_limits<size_t>::max(); + i.total_bytes_free = MallocBlock::FreeQueueSize(); + v->push_back(i); + } + + }; + +static DebugMallocImplementation debug_malloc_implementation; + +REGISTER_MODULE_INITIALIZER(debugallocation, { + // Either we or valgrind will control memory management. We + // register our extension if we're the winner. + if (RunningOnValgrind()) { + // Let Valgrind uses its own malloc (so don't register our extension). + } else { + MallocExtension::Register(&debug_malloc_implementation); + // When the program exits, check all blocks still in the free + // queue for corruption. + atexit(DanglingWriteChecker); + } +}); + +// ========================================================================= // + +// This is mostly the same a cpp_alloc in tcmalloc.cc. +// TODO(csilvers): write a wrapper for new-handler so we don't have to +// copy this code so much. +inline void* debug_cpp_alloc(size_t size, int new_type, bool nothrow) { + for (;;) { + void* p = DebugAllocate(size, new_type); +#ifdef PREANSINEW + return p; +#else + if (p == NULL) { // allocation failed + // Get the current new handler. NB: this function is not + // thread-safe. We make a feeble stab at making it so here, but + // this lock only protects against tcmalloc interfering with + // itself, not with other libraries calling set_new_handler. + std::new_handler nh; + { + SpinLockHolder h(&set_new_handler_lock); + nh = std::set_new_handler(0); + (void) std::set_new_handler(nh); + } +#if (defined(__GNUC__) && !defined(__EXCEPTIONS)) || (defined(_HAS_EXCEPTIONS) && !_HAS_EXCEPTIONS) + if (nh) { + // Since exceptions are disabled, we don't really know if new_handler + // failed. Assume it will abort if it fails. + (*nh)(); + continue; + } + return 0; +#else + // If no new_handler is established, the allocation failed. + if (!nh) { + if (nothrow) return 0; + throw std::bad_alloc(); + } + // Otherwise, try the new_handler. If it returns, retry the + // allocation. If it throws std::bad_alloc, fail the allocation. + // if it throws something else, don't interfere. + try { + (*nh)(); + } catch (const std::bad_alloc&) { + if (!nothrow) throw; + return p; + } +#endif // (defined(__GNUC__) && !defined(__EXCEPTIONS)) || (defined(_HAS_EXCEPTIONS) && !_HAS_EXCEPTIONS) + } else { // allocation success + return p; + } +#endif // PREANSINEW + } } -static void *MemalignOverride(size_t align, size_t size, - const void *caller) __THROW - ATTRIBUTE_SECTION(google_malloc); - -void* operator new(size_t size) throw (std::bad_alloc) - ATTRIBUTE_SECTION(google_malloc); -void* operator new(size_t size, const std::nothrow_t&) __THROW - ATTRIBUTE_SECTION(google_malloc); -void operator delete(void* p) __THROW - ATTRIBUTE_SECTION(google_malloc); -void operator delete(void* p, const std::nothrow_t&) __THROW - ATTRIBUTE_SECTION(google_malloc); -void* operator new[](size_t size) throw (std::bad_alloc) - ATTRIBUTE_SECTION(google_malloc); -void* operator new[](size_t size, const std::nothrow_t&) __THROW - ATTRIBUTE_SECTION(google_malloc); -void operator delete[](void* p) __THROW - ATTRIBUTE_SECTION(google_malloc); -void operator delete[](void* p, const std::nothrow_t&) __THROW - ATTRIBUTE_SECTION(google_malloc); - -extern "C" void* malloc(size_t size) __THROW { - void* ptr = DebugAllocate(size, MallocBlock::kMallocType); +inline void* do_debug_malloc_or_debug_cpp_alloc(size_t size) { + return tc_new_mode ? debug_cpp_alloc(size, MallocBlock::kMallocType, true) + : DebugAllocate(size, MallocBlock::kMallocType); +} + +// Exported routines + +extern "C" PERFTOOLS_DLL_DECL void* tc_malloc(size_t size) __THROW { + void* ptr = do_debug_malloc_or_debug_cpp_alloc(size); MallocHook::InvokeNewHook(ptr, size); return ptr; } -extern "C" void free(void* ptr) __THROW { +extern "C" PERFTOOLS_DLL_DECL void tc_free(void* ptr) __THROW { + MallocHook::InvokeDeleteHook(ptr); + DebugDeallocate(ptr, MallocBlock::kMallocType); +} + +extern "C" PERFTOOLS_DLL_DECL void* tc_calloc(size_t count, size_t size) __THROW { + // Overflow check + const size_t total_size = count * size; + if (size != 0 && total_size / size != count) return NULL; + + void* block = do_debug_malloc_or_debug_cpp_alloc(total_size); + MallocHook::InvokeNewHook(block, total_size); + if (block) memset(block, 0, total_size); + return block; +} + +extern "C" PERFTOOLS_DLL_DECL void tc_cfree(void* ptr) __THROW { MallocHook::InvokeDeleteHook(ptr); DebugDeallocate(ptr, MallocBlock::kMallocType); } -extern "C" void* realloc(void* ptr, size_t size) __THROW { +extern "C" PERFTOOLS_DLL_DECL void* tc_realloc(void* ptr, size_t size) __THROW { if (ptr == NULL) { - ptr = DebugAllocate(size, MallocBlock::kMallocType); + ptr = do_debug_malloc_or_debug_cpp_alloc(size); MallocHook::InvokeNewHook(ptr, size); return ptr; } @@ -1072,20 +1199,59 @@ extern "C" void* realloc(void* ptr, size_t size) __THROW { return p->data_addr(); } -extern "C" void* calloc(size_t count, size_t size) __THROW { - // Overflow check - const size_t total_size = count * size; - if (size != 0 && total_size / size != count) return NULL; +extern "C" PERFTOOLS_DLL_DECL void* tc_new(size_t size) { + void* ptr = debug_cpp_alloc(size, MallocBlock::kNewType, false); + MallocHook::InvokeNewHook(ptr, size); + if (ptr == NULL) { + RAW_LOG(FATAL, "Unable to allocate %"PRIuS" bytes: new failed.", size); + } + return ptr; +} - void* block = DebugAllocate(total_size, MallocBlock::kMallocType); - MallocHook::InvokeNewHook(block, total_size); - if (block) memset(block, 0, total_size); - return block; +extern "C" PERFTOOLS_DLL_DECL void* tc_new_nothrow(size_t size, const std::nothrow_t&) __THROW { + void* ptr = debug_cpp_alloc(size, MallocBlock::kNewType, true); + MallocHook::InvokeNewHook(ptr, size); + return ptr; } -extern "C" void cfree(void* ptr) __THROW { - MallocHook::InvokeDeleteHook(ptr); - DebugDeallocate(ptr, MallocBlock::kMallocType); +extern "C" PERFTOOLS_DLL_DECL void tc_delete(void* p) __THROW { + MallocHook::InvokeDeleteHook(p); + DebugDeallocate(p, MallocBlock::kNewType); +} + +// Some STL implementations explicitly invoke this. +// It is completely equivalent to a normal delete (delete never throws). +extern "C" PERFTOOLS_DLL_DECL void tc_delete_nothrow(void* p, const std::nothrow_t&) __THROW { + MallocHook::InvokeDeleteHook(p); + DebugDeallocate(p, MallocBlock::kNewType); +} + +extern "C" PERFTOOLS_DLL_DECL void* tc_newarray(size_t size) { + void* ptr = debug_cpp_alloc(size, MallocBlock::kArrayNewType, false); + MallocHook::InvokeNewHook(ptr, size); + if (ptr == NULL) { + RAW_LOG(FATAL, "Unable to allocate %"PRIuS" bytes: new[] failed.", size); + } + return ptr; +} + +extern "C" PERFTOOLS_DLL_DECL void* tc_newarray_nothrow(size_t size, const std::nothrow_t&) + __THROW { + void* ptr = debug_cpp_alloc(size, MallocBlock::kArrayNewType, true); + MallocHook::InvokeNewHook(ptr, size); + return ptr; +} + +extern "C" PERFTOOLS_DLL_DECL void tc_deletearray(void* p) __THROW { + MallocHook::InvokeDeleteHook(p); + DebugDeallocate(p, MallocBlock::kArrayNewType); +} + +// Some STL implementations explicitly invoke this. +// It is completely equivalent to a normal delete (delete never throws). +extern "C" PERFTOOLS_DLL_DECL void tc_deletearray_nothrow(void* p, const std::nothrow_t&) __THROW { + MallocHook::InvokeDeleteHook(p); + DebugDeallocate(p, MallocBlock::kArrayNewType); } // Round "value" up to next "alignment" boundary. @@ -1094,6 +1260,7 @@ static intptr_t RoundUp(intptr_t value, intptr_t alignment) { return (value + alignment - 1) & ~(alignment - 1); } +// This is mostly the same as do_memalign in tcmalloc.cc. static void *do_debug_memalign(size_t alignment, size_t size) { // Allocate >= size bytes aligned on "alignment" boundary // "alignment" is a power of two. @@ -1123,83 +1290,10 @@ static void *do_debug_memalign(size_t alignment, size_t size) { return p; } -// Override __libc_memalign in libc on linux boxes. -// They have a bug in libc that causes them (very rarely) to allocate -// with __libc_memalign() yet deallocate with free(). -// This function is an exception to the rule of calling MallocHook method -// from the stack frame of the allocation function; -// heap-checker handles this special case explicitly. -static void *MemalignOverride(size_t align, size_t size, - const void *caller) __THROW { - void *p = do_debug_memalign(align, size); - MallocHook::InvokeNewHook(p, size); - return p; -} -void *(*__memalign_hook)(size_t, size_t, const void *) = MemalignOverride; - -extern "C" void* memalign(size_t align, size_t size) __THROW { - void *p = do_debug_memalign(align, size); - MallocHook::InvokeNewHook(p, size); - return p; -} - -// Implementation taken from tcmalloc/tcmalloc.cc -extern "C" int posix_memalign(void** result_ptr, - size_t align, size_t size) __THROW { - if (((align % sizeof(void*)) != 0) || - ((align & (align - 1)) != 0) || - (align == 0)) { - return EINVAL; - } - - void* result = do_debug_memalign(align, size); - MallocHook::InvokeNewHook(result, size); - if (result == NULL) { - return ENOMEM; - } else { - *result_ptr = result; - return 0; - } -} - -extern "C" void* valloc(size_t size) __THROW { - // Allocate >= size bytes starting on a page boundary - void *p = do_debug_memalign(getpagesize(), size); - MallocHook::InvokeNewHook(p, size); - return p; -} - -extern "C" void* pvalloc(size_t size) __THROW { - // Round size up to a multiple of pages - // then allocate memory on a page boundary - int pagesize = getpagesize(); - size = RoundUp(size, pagesize); - if (size == 0) { // pvalloc(0) should allocate one page, according to - size = pagesize; // http://man.free4web.biz/man3/libmpatrol.3.html - } - void *p = do_debug_memalign(pagesize, size); - MallocHook::InvokeNewHook(p, size); - return p; -} - -extern "C" int mallopt(int cmd, int value) __THROW { - return BASE_MALLOPT(cmd, value); -} - -#ifdef HAVE_STRUCT_MALLINFO -extern "C" struct mallinfo mallinfo(void) __THROW { - return BASE_MALLINFO(); -} -#endif - -// ========================================================================= // - -// Alloc/free stuff for debug operator new & friends - -// This is mostly the same a cpp_alloc in tcmalloc.cc. -inline void* cpp_debug_alloc(size_t size, int new_type, bool nothrow) { +// This is mostly the same as cpp_memalign in tcmalloc.cc. +static void* debug_cpp_memalign(size_t align, size_t size) { for (;;) { - void* p = DebugAllocate(size, new_type); + void* p = do_debug_memalign(align, size); #ifdef PREANSINEW return p; #else @@ -1224,17 +1318,15 @@ inline void* cpp_debug_alloc(size_t size, int new_type, bool nothrow) { return 0; #else // If no new_handler is established, the allocation failed. - if (!nh) { - if (nothrow) return 0; - throw std::bad_alloc(); - } + if (!nh) + return 0; + // Otherwise, try the new_handler. If it returns, retry the // allocation. If it throws std::bad_alloc, fail the allocation. // if it throws something else, don't interfere. try { (*nh)(); } catch (const std::bad_alloc&) { - if (!nothrow) throw; return p; } #endif // (defined(__GNUC__) && !defined(__EXCEPTIONS)) || (defined(_HAS_EXCEPTIONS) && !_HAS_EXCEPTIONS) @@ -1245,185 +1337,89 @@ inline void* cpp_debug_alloc(size_t size, int new_type, bool nothrow) { } } -void* operator new(size_t size) throw (std::bad_alloc) { - void* ptr = cpp_debug_alloc(size, MallocBlock::kNewType, false); - MallocHook::InvokeNewHook(ptr, size); - if (ptr == NULL) { - RAW_LOG(FATAL, "Unable to allocate %"PRIuS" bytes: new failed.", size); - } - return ptr; +inline void* do_debug_memalign_or_debug_cpp_memalign(size_t align, + size_t size) { + return tc_new_mode ? debug_cpp_memalign(align, size) + : do_debug_memalign(align, size); } -void* operator new(size_t size, const std::nothrow_t&) __THROW { - void* ptr = cpp_debug_alloc(size, MallocBlock::kNewType, true); - MallocHook::InvokeNewHook(ptr, size); - return ptr; +extern "C" PERFTOOLS_DLL_DECL void* tc_memalign(size_t align, size_t size) __THROW { + void *p = do_debug_memalign_or_debug_cpp_memalign(align, size); + MallocHook::InvokeNewHook(p, size); + return p; } -void operator delete(void* ptr) __THROW { - MallocHook::InvokeDeleteHook(ptr); - DebugDeallocate(ptr, MallocBlock::kNewType); -} +// Implementation taken from tcmalloc/tcmalloc.cc +extern "C" PERFTOOLS_DLL_DECL int tc_posix_memalign(void** result_ptr, size_t align, size_t size) + __THROW { + if (((align % sizeof(void*)) != 0) || + ((align & (align - 1)) != 0) || + (align == 0)) { + return EINVAL; + } -// Some STL implementations explicitly invoke this. -// It is completely equivalent to a normal delete (delete never throws). -void operator delete(void* ptr, const std::nothrow_t&) __THROW { - MallocHook::InvokeDeleteHook(ptr); - DebugDeallocate(ptr, MallocBlock::kNewType); + void* result = do_debug_memalign_or_debug_cpp_memalign(align, size); + MallocHook::InvokeNewHook(result, size); + if (result == NULL) { + return ENOMEM; + } else { + *result_ptr = result; + return 0; + } } -// ========================================================================= // - -// Alloc/free stuff for debug operator new[] & friends +extern "C" PERFTOOLS_DLL_DECL void* tc_valloc(size_t size) __THROW { + // Allocate >= size bytes starting on a page boundary + void *p = do_debug_memalign_or_debug_cpp_memalign(getpagesize(), size); + MallocHook::InvokeNewHook(p, size); + return p; +} -void* operator new[](size_t size) throw (std::bad_alloc) { - void* ptr = cpp_debug_alloc(size, MallocBlock::kArrayNewType, false); - MallocHook::InvokeNewHook(ptr, size); - if (ptr == NULL) { - RAW_LOG(FATAL, "Unable to allocate %"PRIuS" bytes: new[] failed.", size); +extern "C" PERFTOOLS_DLL_DECL void* tc_pvalloc(size_t size) __THROW { + // Round size up to a multiple of pages + // then allocate memory on a page boundary + int pagesize = getpagesize(); + size = RoundUp(size, pagesize); + if (size == 0) { // pvalloc(0) should allocate one page, according to + size = pagesize; // http://man.free4web.biz/man3/libmpatrol.3.html } - return ptr; + void *p = do_debug_memalign_or_debug_cpp_memalign(pagesize, size); + MallocHook::InvokeNewHook(p, size); + return p; } -void* operator new[](size_t size, const std::nothrow_t&) __THROW { - void* ptr = cpp_debug_alloc(size, MallocBlock::kArrayNewType, true); - MallocHook::InvokeNewHook(ptr, size); - return ptr; +// malloc_stats just falls through to the base implementation. +extern "C" PERFTOOLS_DLL_DECL void tc_malloc_stats(void) __THROW { + BASE_MALLOC_STATS(); } -void operator delete[](void* ptr) __THROW { - MallocHook::InvokeDeleteHook(ptr); - DebugDeallocate(ptr, MallocBlock::kArrayNewType); +extern "C" PERFTOOLS_DLL_DECL int tc_mallopt(int cmd, int value) __THROW { + return BASE_MALLOPT(cmd, value); } -// Some STL implementations explicitly invoke this. -// It is completely equivalent to a normal delete (delete never throws). -void operator delete[](void* ptr, const std::nothrow_t&) __THROW { - MallocHook::InvokeDeleteHook(ptr); - DebugDeallocate(ptr, MallocBlock::kArrayNewType); +#ifdef HAVE_STRUCT_MALLINFO +extern "C" PERFTOOLS_DLL_DECL struct mallinfo tc_mallinfo(void) __THROW { + return BASE_MALLINFO(); } - -// ========================================================================= // - -// The following functions may be called via MallocExtension::instance() -// for memory verification and statistics. -#ifdef TCMALLOC_FOR_DEBUGALLOCATION -// Inherit from tcmalloc's version -typedef TCMallocImplementation ParentImplementation; -#else -// Inherit from default version -typedef MallocExtension ParentImplementation; #endif -class DebugMallocImplementation : public ParentImplementation { - public: - virtual bool GetNumericProperty(const char* name, size_t* value) { - bool result = ParentImplementation::GetNumericProperty(name, value); - if (result && (strcmp(name, "generic.current_allocated_bytes") == 0)) { - // Subtract bytes kept in the free queue - size_t qsize = MallocBlock::FreeQueueSize(); - if (*value >= qsize) { - *value -= qsize; - } - } - return result; - } - - virtual bool VerifyNewMemory(void* p) { - if (p) MallocBlock::FromRawPointer(p)->Check(MallocBlock::kNewType); - return true; - } - - virtual bool VerifyArrayNewMemory(void* p) { - if (p) MallocBlock::FromRawPointer(p)->Check(MallocBlock::kArrayNewType); - return true; - } - - virtual bool VerifyMallocMemory(void* p) { - if (p) MallocBlock::FromRawPointer(p)->Check(MallocBlock::kMallocType); - return true; - } - - virtual bool VerifyAllMemory() { - return MallocBlock::CheckEverything(); - } - - virtual bool MallocMemoryStats(int* blocks, size_t* total, - int histogram[kMallocHistogramSize]) { - return MallocBlock::MemoryStats(blocks, total, histogram); - } - - virtual size_t GetAllocatedSize(void* p) { - if (p) { - return MallocBlock::FromRawPointer(p)->data_size(); - } - return 0; - } - virtual size_t GetEstimatedAllocatedSize(size_t size) { - return size; - } - - virtual void GetFreeListSizes(vector<MallocExtension::FreeListInfo>* v) { - static const char* kDebugFreeQueue = "debug.free_queue"; - - ParentImplementation::GetFreeListSizes(v); - - MallocExtension::FreeListInfo i; - i.type = kDebugFreeQueue; - i.min_object_size = 0; - i.max_object_size = numeric_limits<size_t>::max(); - i.total_bytes_free = MallocBlock::FreeQueueSize(); - v->push_back(i); - } - - }; - -static DebugMallocImplementation debug_malloc_implementation; - -REGISTER_MODULE_INITIALIZER(debugallocation, { - // Either we or valgrind will control memory management. We - // register our extension if we're the winner. - if (RunningOnValgrind()) { - // Let Valgrind uses its own malloc (so don't register our extension). - } else { - MallocExtension::Register(&debug_malloc_implementation); - // When the program exits, check all blocks still in the free - // queue for corruption. - atexit(DanglingWriteChecker); - } -}); - -#ifdef TCMALLOC_FOR_DEBUGALLOCATION - -// Redefine malloc_stats to use tcmalloc's implementation: -extern "C" void malloc_stats(void) __THROW { - do_malloc_stats(); +extern "C" PERFTOOLS_DLL_DECL size_t tc_malloc_size(void* ptr) __THROW { + return BASE_MALLOC_SIZE(ptr); } -// Some library routines on RedHat 9 allocate memory using malloc() -// and free it using __libc_free() (or vice-versa). Since we provide -// our own implementations of malloc/free using tcmalloc.cc, -// we need to make sure that the __libc_XXX variants -// also point to the same implementations. -// -// Note: this might not override __libc_XXX calls withing libc itself, -// but it can be important for other libraries that mention these functions -// or when this code is LD_PRELOAD-ed. -// TODO: In case these __libc_* definitions do not actually matter, -// they should go away from here and from tcmalloc/tcmalloc.cc. -// -extern "C" { - void* __libc_malloc(size_t size) { return malloc(size); } - void __libc_free(void* ptr) { free(ptr); } - void* __libc_realloc(void* ptr, size_t size) { return realloc(ptr, size); } - void* __libc_calloc(size_t n, size_t size) { return calloc(n, size); } - void __libc_cfree(void* ptr) { cfree(ptr); } - void* __libc_memalign(size_t align, size_t s) { return memalign(align, s); } - void* __libc_valloc(size_t size) { return valloc(size); } - void* __libc_pvalloc(size_t size) { return pvalloc(size); } - int __posix_memalign(void** r, size_t a, size_t s) { - return posix_memalign(r, a, s); - } -} +// Override __libc_memalign in libc on linux boxes. +// They have a bug in libc that causes them (very rarely) to allocate +// with __libc_memalign() yet deallocate with free(). +// This function is an exception to the rule of calling MallocHook method +// from the stack frame of the allocation function; +// heap-checker handles this special case explicitly. +static void *MemalignOverride(size_t align, size_t size, const void *caller) + __THROW ATTRIBUTE_SECTION(google_malloc); -#endif // #ifdef TCMALLOC_FOR_DEBUGALLOCATION +static void *MemalignOverride(size_t align, size_t size, const void *caller) + __THROW { + void *p = do_debug_memalign_or_debug_cpp_memalign(align, size); + MallocHook::InvokeNewHook(p, size); + return p; +} +void *(*__memalign_hook)(size_t, size_t, const void *) = MemalignOverride; diff --git a/src/google/tcmalloc.h.in b/src/google/tcmalloc.h.in index cdaaaa0..d42f4e6 100644 --- a/src/google/tcmalloc.h.in +++ b/src/google/tcmalloc.h.in @@ -94,7 +94,7 @@ extern "C" { // OS X: malloc_size() // glibc: malloc_usable_size() // Windows: _msize() - size_t tc_malloc_size(void* ptr) __THROW; + PERFTOOLS_DLL_DECL size_t tc_malloc_size(void* ptr) __THROW; #ifdef __cplusplus PERFTOOLS_DLL_DECL int tc_set_new_mode(int flag) __THROW; diff --git a/src/heap-checker.cc b/src/heap-checker.cc index bfb1cd3..dfda9ad 100644 --- a/src/heap-checker.cc +++ b/src/heap-checker.cc @@ -897,10 +897,19 @@ HeapLeakChecker::ProcMapsResult HeapLeakChecker::UseProcMapsLocked( // do things in this loop. continue; } - // Determine if any shared libraries are present. - if (inode != 0 && strstr(filename, "lib") && strstr(filename, ".so")) { + // Determine if any shared libraries are present. This is the same + // list of extensions as is found in pprof. + if (strstr(filename, ".dll")) { // for windows, which doesn't have inodes saw_shared_lib = true; + } else if (inode != 0) { // ignore fake files + if ((strstr(filename, "lib") && strstr(filename, ".so")) || + // not all .dylib filenames start with lib. .dylib is big enough + // that we are unlikely to get false matches just checking that. + strstr(filename, ".dylib") || strstr(filename, ".bundle")) { + saw_shared_lib = true; + } } + switch (proc_maps_task) { case DISABLE_LIBRARY_ALLOCS: // All lines starting like @@ -1887,6 +1896,11 @@ static bool internal_init_start_has_run = false; // turns out we do not need checking in the end; can stop profiling TurnItselfOffLocked(); return; + } else if (RunningOnValgrind()) { + // There is no point in trying -- we'll just fail. + RAW_LOG(WARNING, "Can't run under Valgrind; will turn itself off"); + TurnItselfOffLocked(); + return; } } diff --git a/src/internal_logging.cc b/src/internal_logging.cc index ea8e56f..4e46ba8 100644 --- a/src/internal_logging.cc +++ b/src/internal_logging.cc @@ -39,6 +39,7 @@ #include <string.h> #include <google/malloc_extension.h> #include "internal_logging.h" +#include "base/logging.h" // for perftools_vsnprintf static const int kLogBufSize = 800; @@ -50,7 +51,7 @@ void TCMalloc_MESSAGE(const char* filename, if (n < kLogBufSize) { va_list ap; va_start(ap, format); - vsnprintf(buf + n, kLogBufSize - n, format, ap); + perftools_vsnprintf(buf + n, kLogBufSize - n, format, ap); va_end(ap); } write(STDERR_FILENO, buf, strlen(buf)); @@ -66,7 +67,7 @@ static void TCMalloc_CRASH_internal(bool dump_stats, char buf[kLogBufSize]; const int n = snprintf(buf, sizeof(buf), "%s:%d] ", filename, line_number); if (n < kLogBufSize) { - vsnprintf(buf + n, kLogBufSize - n, format, ap); + perftools_vsnprintf(buf + n, kLogBufSize - n, format, ap); } write(STDERR_FILENO, buf, strlen(buf)); if (dump_stats) { @@ -99,7 +100,7 @@ void TCMalloc_Printer::printf(const char* format, ...) { if (left_ > 0) { va_list ap; va_start(ap, format); - const int r = vsnprintf(buf_, left_, format, ap); + const int r = perftools_vsnprintf(buf_, left_, format, ap); va_end(ap); if (r < 0) { // Perhaps an old glibc that returns -1 on truncation? diff --git a/src/raw_printer.cc b/src/raw_printer.cc index 019555a..730d6e2 100644 --- a/src/raw_printer.cc +++ b/src/raw_printer.cc @@ -54,7 +54,7 @@ void RawPrinter::Printf(const char* format, ...) { int avail = limit_ - ptr_; // We pass avail+1 to vsnprintf() since that routine needs room // to store the trailing \0. - const int r = vsnprintf(ptr_, avail+1, format, ap); + const int r = perftools_vsnprintf(ptr_, avail+1, format, ap); va_end(ap); if (r < 0) { // Perhaps an old glibc that returns -1 on truncation? diff --git a/src/tcmalloc.cc b/src/tcmalloc.cc index 8d94d20..b037f57 100644 --- a/src/tcmalloc.cc +++ b/src/tcmalloc.cc @@ -97,8 +97,16 @@ #else #include <sys/types.h> #endif -#if defined(HAVE_MALLOC_H) && defined(HAVE_STRUCT_MALLINFO) -#include <malloc.h> // for struct mallinfo +// We only need malloc.h for struct mallinfo. +#ifdef HAVE_STRUCT_MALLINFO +// Malloc can be in several places on older versions of OS X. +# if defined(HAVE_MALLOC_H) +# include <malloc.h> +# elif defined(HAVE_SYS_MALLOC_H) +# include <sys/malloc.h> +# elif defined(HAVE_MALLOC_MALLOC_H) +# include <malloc/malloc.h> +# endif #endif #include <string.h> #ifdef HAVE_PTHREAD @@ -259,7 +267,7 @@ extern "C" { // exception: in windows, by default, we patch our code into these // functions (via src/windows/patch_function.cc) rather than override // them. In that case, we don't want to do this overriding here. -#if !defined(WIN32_DO_PATCHING) && !defined(TCMALLOC_FOR_DEBUGALLOCATION) +#if !defined(WIN32_DO_PATCHING) #if defined(__GNUC__) && !defined(__MACH__) // Potentially faster variants that use the gcc alias extension. @@ -373,7 +381,7 @@ extern "C" { #undef ALIAS -#endif // #ifndef(WIN32_DO_PATCHING) && ndef(TCMALLOC_FOR_DEBUGALLOCATION) +#endif // #ifndef(WIN32_DO_PATCHING) // ----------------------- IMPLEMENTATION ------------------------------- @@ -1474,6 +1482,19 @@ extern "C" PERFTOOLS_DLL_DECL const char* tc_version( return TC_VERSION_STRING; } +// This function behaves similarly to MSVC's _set_new_mode. +// If flag is 0 (default), calls to malloc will behave normally. +// If flag is 1, calls to malloc will behave like calls to new, +// and the std_new_handler will be invoked on failure. +// Returns the previous mode. +extern "C" PERFTOOLS_DLL_DECL int tc_set_new_mode(int flag) __THROW { + int old_mode = tc_new_mode; + tc_new_mode = flag; + return old_mode; +} + +#ifndef TCMALLOC_FOR_DEBUGALLOCATION // debugallocation.cc defines its own + // CAVEAT: The code structure below ensures that MallocHook methods are always // called from the stack frame of the invoked allocation function. // heap-checker.cc depends on this to start a stack trace from @@ -1640,17 +1661,6 @@ extern "C" PERFTOOLS_DLL_DECL size_t tc_malloc_size(void* ptr) __THROW { return GetSizeWithCallback(ptr, &InvalidGetAllocatedSize); } -// This function behaves similarly to MSVC's _set_new_mode. -// If flag is 0 (default), calls to malloc will behave normally. -// If flag is 1, calls to malloc will behave like calls to new, -// and the std_new_handler will be invoked on failure. -// Returns the previous mode. -extern "C" PERFTOOLS_DLL_DECL int tc_set_new_mode(int flag) __THROW { - int old_mode = tc_new_mode; - tc_new_mode = flag; - return old_mode; -} - // Override __libc_memalign in libc on linux boxes specially. // They have a bug in libc that causes them to (very rarely) allocate @@ -1659,7 +1669,6 @@ extern "C" PERFTOOLS_DLL_DECL int tc_set_new_mode(int flag) __THROW { // This function is an exception to the rule of calling MallocHook method // from the stack frame of the allocation function; // heap-checker handles this special case explicitly. -#ifndef TCMALLOC_FOR_DEBUGALLOCATION static void *MemalignOverride(size_t align, size_t size, const void *caller) __THROW ATTRIBUTE_SECTION(google_malloc); @@ -1670,4 +1679,5 @@ static void *MemalignOverride(size_t align, size_t size, const void *caller) return result; } void *(*__memalign_hook)(size_t, size_t, const void *) = MemalignOverride; + #endif // #ifndef TCMALLOC_FOR_DEBUGALLOCATION diff --git a/src/tests/debugallocation_test.cc b/src/tests/debugallocation_test.cc index dd5af13..07b8604 100644 --- a/src/tests/debugallocation_test.cc +++ b/src/tests/debugallocation_test.cc @@ -220,7 +220,7 @@ TEST(DebugAllocationTest, StackTraceWithDanglingWriteAtExitTest) { *x = 1; // verify that we also get a stack trace when we have a dangling write. // The " @ " is part of the stack trace output. - IF_DEBUG_EXPECT_DEATH(exit(0), " @ .* main"); + IF_DEBUG_EXPECT_DEATH(exit(0), " @ .*main"); *x = old_x_value; // restore x so that the test can exit successfully. } diff --git a/src/tests/heap-checker_unittest.cc b/src/tests/heap-checker_unittest.cc index b282941..e33e068 100644 --- a/src/tests/heap-checker_unittest.cc +++ b/src/tests/heap-checker_unittest.cc @@ -76,11 +76,6 @@ #include <sys/mman.h> #endif #include <fcntl.h> // for open(), close() -// FreeBSD has malloc.h, but complains if you use it -#if defined(HAVE_MALLOC_H) && !defined(__FreeBSD__) -#include <malloc.h> -#endif - #ifdef HAVE_EXECINFO_H #include <execinfo.h> // backtrace #endif @@ -684,7 +679,7 @@ static void ScopedDisabledLeaks() { HeapLeakChecker::Disabler disabler; AllocHidden(3 * sizeof(int)); TransLeaks(); - malloc(10); // Direct leak + (void)malloc(10); // Direct leak } // have different disabled leaks diff --git a/src/tests/memalign_unittest.cc b/src/tests/memalign_unittest.cc index d5b60db..ce2c1f3 100644 --- a/src/tests/memalign_unittest.cc +++ b/src/tests/memalign_unittest.cc @@ -57,8 +57,13 @@ #ifdef HAVE_UNISTD_H #include <unistd.h> // for getpagesize() #endif -#ifdef HAVE_MALLOC_H -#include <malloc.h> +// Malloc can be in several places on older versions of OS X. +#if defined(HAVE_MALLOC_H) +#include <malloc.h> // for memalign() and valloc() +#elif defined(HAVE_SYS_MALLOC_H) +#include <sys/malloc.h> +#elif defined(HAVE_MALLOC_MALLOC_H) +#include <malloc/malloc.h> #endif #include "base/basictypes.h" #include "base/logging.h" diff --git a/src/tests/sampler_test.cc b/src/tests/sampler_test.cc index 045cd02..31c87cd 100755 --- a/src/tests/sampler_test.cc +++ b/src/tests/sampler_test.cc @@ -87,7 +87,7 @@ static std::string StringPrintf(const char* format, ...) { char buf[256]; // should be big enough for all logging va_list ap; va_start(ap, format); - vsnprintf(buf, sizeof(buf), format, ap); + perftools_vsnprintf(buf, sizeof(buf), format, ap); va_end(ap); return buf; } diff --git a/src/windows/config.h b/src/windows/config.h index fb0327d..1d93c4f 100644 --- a/src/windows/config.h +++ b/src/windows/config.h @@ -210,7 +210,7 @@ #define PACKAGE_NAME "google-perftools" /* Define to the full name and version of this package. */ -#define PACKAGE_STRING "google-perftools 1.4" +#define PACKAGE_STRING "google-perftools 1.7" /* Define to the one symbol short name of this package. */ #define PACKAGE_TARNAME "google-perftools" @@ -219,7 +219,7 @@ #undef PACKAGE_URL /* Define to the version of this package. */ -#define PACKAGE_VERSION "1.4" +#define PACKAGE_VERSION "1.7" /* How to access the PC from a struct ucontext */ #undef PC_FROM_UCONTEXT diff --git a/src/windows/google/tcmalloc.h b/src/windows/google/tcmalloc.h.in index 5bd4c59..a031b35 100644 --- a/src/windows/google/tcmalloc.h +++ b/src/windows/google/tcmalloc.h.in @@ -29,18 +29,12 @@ * * --- * Author: Sanjay Ghemawat <opensource@google.com> - * .h file by Craig Silverstein <opensource@google.com> + * .h.in file by Craig Silverstein <opensource@google.com> */ #ifndef TCMALLOC_TCMALLOC_H_ #define TCMALLOC_TCMALLOC_H_ -// Define the version number so folks can check against it -#define TC_VERSION_MAJOR 1 -#define TC_VERSION_MINOR 4 -#define TC_VERSION_PATCH "" -#define TC_VERSION_STRING "google-perftools 1.4" - // __THROW is defined in glibc systems. It means, counter-intuitively, // "This function will never throw an exception." It's an optional // optimization tool, but we may need to use it to match glibc prototypes. @@ -48,6 +42,11 @@ # define __THROW /* __THROW is just an optimization, so ok to make it "" */ #endif +// Define the version number so folks can check against it +#define TC_VERSION_MAJOR @TC_VERSION_MAJOR@ +#define TC_VERSION_MINOR @TC_VERSION_MINOR@ +#define TC_VERSION_PATCH "@TC_VERSION_PATCH@" +#define TC_VERSION_STRING "google-perftools @TC_VERSION_MAJOR@.@TC_VERSION_MINOR@@TC_VERSION_PATCH@" #include <stdlib.h> // for struct mallinfo, if it's defined diff --git a/src/windows/port.cc b/src/windows/port.cc index 32f3c31..aa972d0 100644 --- a/src/windows/port.cc +++ b/src/windows/port.cc @@ -49,24 +49,6 @@ // ----------------------------------------------------------------------- // Basic libraries -// These call the windows _vsnprintf, but always NUL-terminate. -int safe_vsnprintf(char *str, size_t size, const char *format, va_list ap) { - if (size == 0) // not even room for a \0? - return -1; // not what C99 says to do, but what windows does - str[size-1] = '\0'; - return _vsnprintf(str, size-1, format, ap); -} - -#ifndef HAVE_SNPRINTF -int snprintf(char *str, size_t size, const char *format, ...) { - va_list ap; - va_start(ap, format); - const int r = vsnprintf(str, size, format, ap); - va_end(ap); - return r; -} -#endif - int getpagesize() { static int pagesize = 0; if (pagesize == 0) { @@ -98,6 +80,7 @@ extern "C" PERFTOOLS_DLL_DECL void WriteToStderr(const char* buf, int len) { // ----------------------------------------------------------------------- // Threads code +// Declared (not extern "C") in thread_cache.h bool CheckIfKernelSupportsTLS() { // TODO(csilvers): return true (all win's since win95, at least, support this) return false; @@ -186,7 +169,7 @@ BOOL WINAPI DllMain(HINSTANCE h, DWORD dwReason, PVOID pv) { #endif // #ifdef _MSC_VER -pthread_key_t PthreadKeyCreate(void (*destr_fn)(void*)) { +extern "C" pthread_key_t PthreadKeyCreate(void (*destr_fn)(void*)) { // Semantics are: we create a new key, and then promise to call // destr_fn with TlsGetValue(key) when the thread is destroyed // (as long as TlsGetValue(key) is not NULL). @@ -200,6 +183,30 @@ pthread_key_t PthreadKeyCreate(void (*destr_fn)(void*)) { return key; } +// NOTE: this is Win2K and later. For Win98 we could use a CRITICAL_SECTION... +extern "C" int perftools_pthread_once(pthread_once_t *once_control, + void (*init_routine)(void)) { + // Try for a fast path first. Note: this should be an acquire semantics read. + // It is on x86 and x64, where Windows runs. + if (*once_control != 1) { + while (true) { + switch (InterlockedCompareExchange(once_control, 2, 0)) { + case 0: + init_routine(); + InterlockedExchange(once_control, 1); + return 0; + case 1: + // The initializer has already been executed + return 0; + default: + // The initializer is being processed by another thread + SwitchToThread(); + } + } + } + return 0; +} + // ----------------------------------------------------------------------- // These functions replace system-alloc.cc diff --git a/src/windows/port.h b/src/windows/port.h index ff6b714..0faba01 100644 --- a/src/windows/port.h +++ b/src/windows/port.h @@ -40,8 +40,8 @@ #ifndef GOOGLE_BASE_WINDOWS_H_ #define GOOGLE_BASE_WINDOWS_H_ -// You should never include this file directly, but always include it -// from either config.h (MSVC) or mingw.h (MinGW/msys). +/* You should never include this file directly, but always include it + from either config.h (MSVC) or mingw.h (MinGW/msys). */ #if !defined(GOOGLE_PERFTOOLS_WINDOWS_CONFIG_H_) && \ !defined(GOOGLE_PERFTOOLS_WINDOWS_MINGW_H_) # error "port.h should only be included from config.h or mingw.h" @@ -54,21 +54,45 @@ #endif #include <windows.h> #include <io.h> /* because we so often use open/close/etc */ +#include <direct.h> /* for _getcwd */ #include <process.h> /* for _getpid */ +#include <limits.h> /* for PATH_MAX */ #include <stdarg.h> /* for va_list */ #include <stdio.h> /* need this to override stdio's (v)snprintf */ - -// 4018: signed/unsigned mismatch is common (and ok for signed_i < unsigned_i) -// 4244: otherwise we get problems when substracting two size_t's to an int -// 4288: VC++7 gets confused when a var is defined in a loop and then after it -// 4267: too many false positives for "conversion gives possible data loss" -// 4290: it's ok windows ignores the "throw" directive -// 4996: Yes, we're ok using "unsafe" functions like vsnprintf and getenv() +#include <sys/types.h> /* for _off_t */ +#include <assert.h> +#include <stdlib.h> /* for rand, srand, _strtoxxx */ + +/* + * 4018: signed/unsigned mismatch is common (and ok for signed_i < unsigned_i) + * 4244: otherwise we get problems when substracting two size_t's to an int + * 4288: VC++7 gets confused when a var is defined in a loop and then after it + * 4267: too many false positives for "conversion gives possible data loss" + * 4290: it's ok windows ignores the "throw" directive + * 4996: Yes, we're ok using "unsafe" functions like vsnprintf and getenv() + */ #ifdef _MSC_VER #pragma warning(disable:4018 4244 4288 4267 4290 4996) #endif -// ----------------------------------- BASIC TYPES +#ifndef __cplusplus +/* MSVC does not support C99 */ +# if !defined(__STDC_VERSION__) || __STDC_VERSION__ < 199901L +# ifdef _MSC_VER +# define inline __inline +# else +# define inline static +# endif +# endif +#endif + +#ifdef __cplusplus +# define EXTERN_C extern "C" +#else +# define EXTERN_C extern +#endif + +/* ----------------------------------- BASIC TYPES */ #ifndef HAVE_STDINT_H #ifndef HAVE___INT64 /* we need to have all the __intX names */ @@ -83,53 +107,78 @@ typedef unsigned __int8 uint8_t; typedef unsigned __int16 uint16_t; typedef unsigned __int32 uint32_t; typedef unsigned __int64 uint64_t; -#endif // #ifndef HAVE_STDINT_H +#endif /* #ifndef HAVE_STDINT_H */ -// I guess MSVC's <types.h> doesn't include ssize_t by default? +/* I guess MSVC's <types.h> doesn't include ssize_t by default? */ #ifdef _MSC_VER typedef intptr_t ssize_t; #endif -// ----------------------------------- THREADS +/* ----------------------------------- THREADS */ -#ifndef HAVE_PTHREAD // not true for MSVC, but may be true for MSYS +#ifndef HAVE_PTHREAD /* not true for MSVC, but may be true for MSYS */ typedef DWORD pthread_t; typedef DWORD pthread_key_t; typedef LONG pthread_once_t; -enum { PTHREAD_ONCE_INIT = 0 }; // important that this be 0! for SpinLock -#define pthread_self GetCurrentThreadId -#define pthread_equal(pthread_t_1, pthread_t_2) ((pthread_t_1)==(pthread_t_2)) +enum { PTHREAD_ONCE_INIT = 0 }; /* important that this be 0! for SpinLock */ + +inline pthread_t pthread_self(void) { + return GetCurrentThreadId(); +} #ifdef __cplusplus -// This replaces maybe_threads.{h,cc} -extern pthread_key_t PthreadKeyCreate(void (*destr_fn)(void*)); // in port.cc -#define perftools_pthread_key_create(pkey, destr_fn) \ - *(pkey) = PthreadKeyCreate(destr_fn) +inline bool pthread_equal(pthread_t left, pthread_t right) { + return left == right; +} + +/* This replaces maybe_threads.{h,cc} */ +EXTERN_C pthread_key_t PthreadKeyCreate(void (*destr_fn)(void*)); /* port.cc */ + +inline int perftools_pthread_key_create(pthread_key_t *pkey, + void (*destructor)(void*)) { + pthread_key_t key = PthreadKeyCreate(destructor); + if (key != TLS_OUT_OF_INDEXES) { + *(pkey) = key; + return 0; + } else { + return GetLastError(); + } +} + inline void* perftools_pthread_getspecific(DWORD key) { DWORD err = GetLastError(); void* rv = TlsGetValue(key); if (err) SetLastError(err); return rv; } -#define perftools_pthread_setspecific(key, val) \ - TlsSetValue((key), (val)) -// NOTE: this is Win2K and later. For Win98 we could use a CRITICAL_SECTION... -#define perftools_pthread_once(once, init) do { \ - if (InterlockedCompareExchange(once, 1, 0) == 0) (init)(); \ -} while (0) -#endif // __cplusplus -#endif // HAVE_PTHREAD - -// __declspec(thread) isn't usable in a dll opened via LoadLibrary(). -// But it doesn't work to LoadLibrary() us anyway, because of all the -// things we need to do before main()! So this kind of TLS is safe for us. + +inline int perftools_pthread_setspecific(pthread_key_t key, const void *value) { + if (TlsSetValue(key, (LPVOID)value)) + return 0; + else + return GetLastError(); +} + +EXTERN_C int perftools_pthread_once(pthread_once_t *once_control, + void (*init_routine)(void)); + +#endif /* __cplusplus */ +#endif /* HAVE_PTHREAD */ + +/* + * __declspec(thread) isn't usable in a dll opened via LoadLibrary(). + * But it doesn't work to LoadLibrary() us anyway, because of all the + * things we need to do before main()! So this kind of TLS is safe for us. + */ #define __thread __declspec(thread) -// This code is obsolete, but I keep it around in case we are ever in -// an environment where we can't or don't want to use google spinlocks -// (from base/spinlock.{h,cc}). In that case, uncommenting this out, -// and removing spinlock.cc from the build, should be enough to revert -// back to using native spinlocks. +/* + * This code is obsolete, but I keep it around in case we are ever in + * an environment where we can't or don't want to use google spinlocks + * (from base/spinlock.{h,cc}). In that case, uncommenting this out, + * and removing spinlock.cc from the build, should be enough to revert + * back to using native spinlocks. + */ #if 0 // Windows uses a spinlock internally for its mutexes, making our life easy! // However, the Windows spinlock must always be initialized, making life hard, @@ -197,51 +246,80 @@ class SpinLockHolder { // Acquires a spinlock for as long as the scope lasts // This keeps us from using base/spinlock.h's implementation of SpinLock. #define BASE_SPINLOCK_H_ 1 -#endif // #if 0 - -// This replaces testutil.{h,cc} -extern PERFTOOLS_DLL_DECL void RunInThread(void (*fn)()); -extern PERFTOOLS_DLL_DECL void RunManyInThread(void (*fn)(), int count); -extern PERFTOOLS_DLL_DECL void RunManyInThreadWithId(void (*fn)(int), int count, - int stacksize); +#endif /* #if 0 */ +/* ----------------------------------- MMAP and other memory allocation */ -// ----------------------------------- MMAP and other memory allocation - -#ifndef HAVE_MMAP // not true for MSVC, but may be true for msys +#ifndef HAVE_MMAP /* not true for MSVC, but may be true for msys */ #define MAP_FAILED 0 -#define MREMAP_FIXED 2 // the value in linux, though it doesn't really matter -// These, when combined with the mmap invariants below, yield the proper action +#define MREMAP_FIXED 2 /* the value in linux, though it doesn't really matter */ +/* These, when combined with the mmap invariants below, yield the proper action */ #define PROT_READ PAGE_READWRITE #define PROT_WRITE PAGE_READWRITE #define MAP_ANONYMOUS MEM_RESERVE #define MAP_PRIVATE MEM_COMMIT -#define MAP_SHARED MEM_RESERVE // value of this #define is 100% arbitrary +#define MAP_SHARED MEM_RESERVE /* value of this #define is 100% arbitrary */ -// VirtualAlloc is only a replacement for mmap when certain invariants are kept -#define mmap(start, length, prot, flags, fd, offset) \ - ( (start) == NULL && (fd) == -1 && (offset) == 0 && \ - (prot) == (PROT_READ|PROT_WRITE) && (flags) == (MAP_PRIVATE|MAP_ANONYMOUS)\ - ? VirtualAlloc(0, length, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE) \ - : NULL ) +#if __STDC__ +typedef _off_t off_t; +#endif -#define munmap(start, length) (VirtualFree(start, 0, MEM_RELEASE) ? 0 : -1) -#endif // HAVE_MMAP +/* VirtualAlloc only replaces for mmap when certain invariants are kept. */ +inline void *mmap(void *addr, size_t length, int prot, int flags, + int fd, off_t offset) { + if (addr == NULL && fd == -1 && offset == 0 && + prot == (PROT_READ|PROT_WRITE) && flags == (MAP_PRIVATE|MAP_ANONYMOUS)) { + return VirtualAlloc(0, length, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); + } else { + return NULL; + } +} -// We could maybe use VirtualAlloc for sbrk as well, but no need -#define sbrk(increment) ( (void*)-1 ) // sbrk returns -1 on failure +inline int munmap(void *addr, size_t length) { + return VirtualFree(addr, 0, MEM_RELEASE) ? 0 : -1; +} +#endif /* HAVE_MMAP */ +/* We could maybe use VirtualAlloc for sbrk as well, but no need */ +inline void *sbrk(intptr_t increment) { + // sbrk returns -1 on failure + return (void*)-1; +} -// ----------------------------------- STRING ROUTINES -// We can't just use _vsnprintf and _snprintf as drop-in-replacements, -// because they don't always NUL-terminate. :-( We also can't use the -// name vsnprintf, since windows defines that (but not snprintf (!)). -extern PERFTOOLS_DLL_DECL int snprintf(char *str, size_t size, - const char *format, ...); -extern PERFTOOLS_DLL_DECL int safe_vsnprintf(char *str, size_t size, - const char *format, va_list ap); -#define vsnprintf(str, size, format, ap) safe_vsnprintf(str, size, format, ap) +/* ----------------------------------- STRING ROUTINES */ + +/* + * We can't just use _vsnprintf and _snprintf as drop-in-replacements, + * because they don't always NUL-terminate. :-( We also can't use the + * name vsnprintf, since windows defines that (but not snprintf (!)). + */ +#if defined(_MSC_VER) && _MSC_VER >= 1400 +/* We can use safe CRT functions, which the required functionality */ +inline int perftools_vsnprintf(char *str, size_t size, const char *format, + va_list ap) { + return vsnprintf_s(str, size, _TRUNCATE, format, ap); +} +#else +inline int perftools_vsnprintf(char *str, size_t size, const char *format, + va_list ap) { + if (size == 0) /* not even room for a \0? */ + return -1; /* not what C99 says to do, but what windows does */ + str[size-1] = '\0'; + return _vsnprintf(str, size-1, format, ap); +} +#endif + +#ifndef HAVE_SNPRINTF +inline int snprintf(char *str, size_t size, const char *format, ...) { + va_list ap; + int r; + va_start(ap, format); + r = perftools_vsnprintf(str, size, format, ap); + va_end(ap); + return r; +} +#endif #define PRIx64 "I64x" #define SCNx64 "I64x" @@ -256,84 +334,132 @@ extern PERFTOOLS_DLL_DECL int safe_vsnprintf(char *str, size_t size, # define PRIxPTR "lx" #endif -// ----------------------------------- FILE IO +/* ----------------------------------- FILE IO */ + #ifndef PATH_MAX #define PATH_MAX 1024 #endif #ifndef __MINGW32__ enum { STDIN_FILENO = 0, STDOUT_FILENO = 1, STDERR_FILENO = 2 }; #endif -#define getcwd _getcwd -#define access _access -#define open _open -#define read _read -#define write _write -#define lseek _lseek -#define close _close -#define popen _popen -#define pclose _pclose -#define mkdir(dirname, mode) _mkdir(dirname) #ifndef O_RDONLY #define O_RDONLY _O_RDONLY #endif -#ifdef __cplusplus -extern "C" +#if __STDC__ && !defined(__MINGW32__) +/* These functions are considered non-standard */ +inline int access(const char *pathname, int mode) { + return _access(pathname, mode); +} +inline int open(const char *pathname, int flags, int mode = 0) { + return _open(pathname, flags, mode); +} +inline int close(int fd) { + return _close(fd); +} +inline ssize_t read(int fd, void *buf, size_t count) { + return _read(fd, buf, count); +} +inline ssize_t write(int fd, const void *buf, size_t count) { + return _write(fd, buf, count); +} +inline off_t lseek(int fd, off_t offset, int whence) { + return _lseek(fd, offset, whence); +} +inline char *getcwd(char *buf, size_t size) { + return _getcwd(buf, size); +} +inline int mkdir(const char *pathname, int) { + return _mkdir(pathname); +} #endif -PERFTOOLS_DLL_DECL void WriteToStderr(const char* buf, int len); -// ----------------------------------- SYSTEM/PROCESS -typedef int pid_t; -#define getpid _getpid -#define getppid() (0) +inline FILE *popen(const char *command, const char *type) { + return _popen(command, type); +} +inline int pclose(FILE *stream) { + return _pclose(stream); +} + +EXTERN_C PERFTOOLS_DLL_DECL void WriteToStderr(const char* buf, int len); + +/* ----------------------------------- SYSTEM/PROCESS */ -// Handle case when poll is used to simulate sleep. -#define poll(r, w, t) \ - do { \ - assert(r == 0); \ - assert(w == 0); \ - Sleep(t); \ - } while(0) +typedef int pid_t; +#if __STDC__ +inline pid_t getpid(void) { return _getpid(); } +#endif +inline pid_t getppid(void) { return 0; } + +/* Handle case when poll is used to simulate sleep. */ +inline int poll(struct pollfd* fds, int nfds, int timeout) { + assert(fds == NULL); + assert(nfds == 0); + Sleep(timeout); + return 0; +} -extern PERFTOOLS_DLL_DECL int getpagesize(); // in port.cc +EXTERN_C int getpagesize(); /* in port.cc */ -// ----------------------------------- OTHER +/* ----------------------------------- OTHER */ -#define srandom srand -#define random rand -#define sleep(t) Sleep(t * 1000) +inline void srandom(unsigned int seed) { srand(seed); } +inline long random(void) { return rand(); } +inline unsigned int sleep(unsigned int seconds) { + Sleep(seconds * 1000); + return 0; +} struct timespec { int tv_sec; int tv_nsec; }; -#define nanosleep(tm_ptr, ignored) \ - Sleep((tm_ptr)->tv_sec * 1000 + (tm_ptr)->tv_nsec / 1000000) +inline int nanosleep(const struct timespec *req, struct timespec *rem) { + Sleep(req->tv_sec * 1000 + req->tv_nsec / 1000000); + return 0; +} #ifndef __MINGW32__ -#define strtoq _strtoi64 -#define strtouq _strtoui64 -#define strtoll _strtoi64 -#define strtoull _strtoui64 -#define atoll _atoi64 +inline long long int strtoll(const char *nptr, char **endptr, int base) { + return _strtoi64(nptr, endptr, base); +} +inline unsigned long long int strtoull(const char *nptr, char **endptr, + int base) { + return _strtoui64(nptr, endptr, base); +} +inline long long int strtoq(const char *nptr, char **endptr, int base) { + return _strtoi64(nptr, endptr, base); +} +inline unsigned long long int strtouq(const char *nptr, char **endptr, + int base) { + return _strtoui64(nptr, endptr, base); +} +inline long long atoll(const char *nptr) { + return _atoi64(nptr); +} #endif #define __THROW throw() -// ----------------------------------- TCMALLOC-SPECIFIC +/* ----------------------------------- TCMALLOC-SPECIFIC */ -// tcmalloc.cc calls this so we can patch VirtualAlloc() et al. -extern PERFTOOLS_DLL_DECL void PatchWindowsFunctions(); +/* tcmalloc.cc calls this so we can patch VirtualAlloc() et al. */ +extern void PatchWindowsFunctions(); // ----------------------------------- BUILD-SPECIFIC -// windows/port.h defines compatibility APIs for several .h files, which -// we therefore shouldn't be #including directly. This hack keeps us from -// doing so. TODO(csilvers): do something more principled. +/* + * windows/port.h defines compatibility APIs for several .h files, which + * we therefore shouldn't be #including directly. This hack keeps us from + * doing so. TODO(csilvers): do something more principled. + */ #define GOOGLE_MAYBE_THREADS_H_ 1 #endif /* _WIN32 */ +#undef inline +#undef EXTERN_C + #endif /* GOOGLE_BASE_WINDOWS_H_ */ |