diff options
Diffstat (limited to 'third_party/tcmalloc/chromium/src/windows')
7 files changed, 466 insertions, 170 deletions
diff --git a/third_party/tcmalloc/chromium/src/windows/config.h b/third_party/tcmalloc/chromium/src/windows/config.h index b5d9bb6..1d93c4f 100644 --- a/third_party/tcmalloc/chromium/src/windows/config.h +++ b/third_party/tcmalloc/chromium/src/windows/config.h @@ -92,7 +92,7 @@ #undef HAVE_LINUX_PTRACE_H /* Define to 1 if you have the <malloc.h> header file. */ -#undef HAVE_MALLOC_H +#define HAVE_MALLOC_H 1 /* Define to 1 if you have the <memory.h> header file. */ #undef HAVE_MEMORY_H @@ -136,6 +136,9 @@ /* Define to 1 if the system has the type `struct mallinfo'. */ #undef HAVE_STRUCT_MALLINFO +/* Define to 1 if you have the <sys/param.h> header file. */ +#undef HAVE_SYS_PARAM_H + /* Define to 1 if you have the <sys/prctl.h> header file. */ #undef HAVE_SYS_PRCTL_H @@ -154,7 +157,7 @@ /* Define to 1 if you have the <sys/types.h> header file. */ #define HAVE_SYS_TYPES_H 1 -/* Define to 1 if you have the <sys/ucontext.h> header file. */ +/* <sys/ucontext.h> is broken on redhat 7 */ #undef HAVE_SYS_UCONTEXT_H /* Define to 1 if you have the <sys/wait.h> header file. */ @@ -172,6 +175,9 @@ /* Define to 1 if you have the <unwind.h> header file. */ #undef HAVE_UNWIND_H +/* Define to 1 if you have the <valgrind.h> header file. */ +#undef HAVE_VALGRIND_H + /* define if your compiler has __attribute__ */ #undef HAVE___ATTRIBUTE__ @@ -187,6 +193,10 @@ /* Define to 1 if int32_t is equivalent to intptr_t */ #undef INT32_EQUALS_INTPTR +/* Define to the sub-directory in which libtool stores uninstalled libraries. + */ +#undef LT_OBJDIR + /* Define to 1 if your C compiler doesn't accept -c and -o together. */ #undef NO_MINUS_C_MINUS_O @@ -200,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" @@ -209,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/third_party/tcmalloc/chromium/src/windows/google/tcmalloc.h b/third_party/tcmalloc/chromium/src/windows/google/tcmalloc.h index 663b7f9..f6c17f5 100644 --- a/third_party/tcmalloc/chromium/src/windows/google/tcmalloc.h +++ b/third_party/tcmalloc/chromium/src/windows/google/tcmalloc.h @@ -35,12 +35,6 @@ #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 1 +#define TC_VERSION_MINOR 7 +#define TC_VERSION_PATCH "" +#define TC_VERSION_STRING "google-perftools 1.7" #include <stdlib.h> // for struct mallinfo, if it's defined @@ -90,6 +89,13 @@ extern "C" { PERFTOOLS_DLL_DECL struct mallinfo tc_mallinfo(void) __THROW; #endif + // This is an alias for MallocExtension::instance()->GetAllocatedSize(). + // It is equivalent to + // OS X: malloc_size() + // glibc: malloc_usable_size() + // Windows: _msize() + PERFTOOLS_DLL_DECL size_t tc_malloc_size(void* ptr) __THROW; + #ifdef __cplusplus PERFTOOLS_DLL_DECL int tc_set_new_mode(int flag) __THROW; PERFTOOLS_DLL_DECL void* tc_new(size_t size); diff --git a/third_party/tcmalloc/chromium/src/windows/google/tcmalloc.h.in b/third_party/tcmalloc/chromium/src/windows/google/tcmalloc.h.in new file mode 100644 index 0000000..a031b35 --- /dev/null +++ b/third_party/tcmalloc/chromium/src/windows/google/tcmalloc.h.in @@ -0,0 +1,116 @@ +/* Copyright (c) 2003, 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: Sanjay Ghemawat <opensource@google.com> + * .h.in file by Craig Silverstein <opensource@google.com> + */ + +#ifndef TCMALLOC_TCMALLOC_H_ +#define TCMALLOC_TCMALLOC_H_ + +// __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. +#ifndef __THROW /* I guess we're not on a glibc system */ +# 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 + +// Annoying stuff for windows -- makes sure clients can import these functions +#ifndef PERFTOOLS_DLL_DECL +# ifdef _WIN32 +# define PERFTOOLS_DLL_DECL __declspec(dllimport) +# else +# define PERFTOOLS_DLL_DECL +# endif +#endif + +#ifdef __cplusplus +#include <new> // for std::nothrow_t + +extern "C" { +#endif + // Returns a human-readable version string. If major, minor, + // and/or patch are not NULL, they are set to the major version, + // minor version, and patch-code (a string, usually ""). + PERFTOOLS_DLL_DECL const char* tc_version(int* major, int* minor, + const char** patch) __THROW; + + PERFTOOLS_DLL_DECL void* tc_malloc(size_t size) __THROW; + PERFTOOLS_DLL_DECL void tc_free(void* ptr) __THROW; + PERFTOOLS_DLL_DECL void* tc_realloc(void* ptr, size_t size) __THROW; + PERFTOOLS_DLL_DECL void* tc_calloc(size_t nmemb, size_t size) __THROW; + PERFTOOLS_DLL_DECL void tc_cfree(void* ptr) __THROW; + + PERFTOOLS_DLL_DECL void* tc_memalign(size_t __alignment, + size_t __size) __THROW; + PERFTOOLS_DLL_DECL int tc_posix_memalign(void** ptr, + size_t align, size_t size) __THROW; + PERFTOOLS_DLL_DECL void* tc_valloc(size_t __size) __THROW; + PERFTOOLS_DLL_DECL void* tc_pvalloc(size_t __size) __THROW; + + PERFTOOLS_DLL_DECL void tc_malloc_stats(void) __THROW; + PERFTOOLS_DLL_DECL int tc_mallopt(int cmd, int value) __THROW; +#if 0 + PERFTOOLS_DLL_DECL struct mallinfo tc_mallinfo(void) __THROW; +#endif + + // This is an alias for MallocExtension::instance()->GetAllocatedSize(). + // It is equivalent to + // OS X: malloc_size() + // glibc: malloc_usable_size() + // Windows: _msize() + PERFTOOLS_DLL_DECL size_t tc_malloc_size(void* ptr) __THROW; + +#ifdef __cplusplus + PERFTOOLS_DLL_DECL int tc_set_new_mode(int flag) __THROW; + PERFTOOLS_DLL_DECL void* tc_new(size_t size); + PERFTOOLS_DLL_DECL void* tc_new_nothrow(size_t size, + const std::nothrow_t&) __THROW; + PERFTOOLS_DLL_DECL void tc_delete(void* p) __THROW; + PERFTOOLS_DLL_DECL void tc_delete_nothrow(void* p, + const std::nothrow_t&) __THROW; + PERFTOOLS_DLL_DECL void* tc_newarray(size_t size); + PERFTOOLS_DLL_DECL void* tc_newarray_nothrow(size_t size, + const std::nothrow_t&) __THROW; + PERFTOOLS_DLL_DECL void tc_deletearray(void* p) __THROW; + PERFTOOLS_DLL_DECL void tc_deletearray_nothrow(void* p, + const std::nothrow_t&) __THROW; +} +#endif + +#endif // #ifndef TCMALLOC_TCMALLOC_H_ diff --git a/third_party/tcmalloc/chromium/src/windows/mingw.h b/third_party/tcmalloc/chromium/src/windows/mingw.h index e69b5da..747b285 100644 --- a/third_party/tcmalloc/chromium/src/windows/mingw.h +++ b/third_party/tcmalloc/chromium/src/windows/mingw.h @@ -45,10 +45,23 @@ # define PERFTOOLS_NO_ALIGNED_MALLOC 1 #endif +// This must be defined before the windows.h is included. We need at +// least 0x0400 for mutex.h to have access to TryLock, and at least +// 0x0501 for patch_functions.cc to have access to GetModuleHandleEx. +// (This latter is an optimization we could take out if need be.) +#ifndef _WIN32_WINNT +# define _WIN32_WINNT 0x0501 +#endif + #include "windows/port.h" #define HAVE_SNPRINTF 1 +// Some mingw distributions have a pthreads wrapper, but it doesn't +// work as well as native windows spinlocks (at least for us). So +// pretend the pthreads wrapper doesn't exist, even when it does. +#undef HAVE_PTHREAD + #endif /* __MINGW32__ */ #endif /* GOOGLE_PERFTOOLS_WINDOWS_MINGW_H_ */ diff --git a/third_party/tcmalloc/chromium/src/windows/patch_functions.cc b/third_party/tcmalloc/chromium/src/windows/patch_functions.cc index deb841b..f837e7a 100644 --- a/third_party/tcmalloc/chromium/src/windows/patch_functions.cc +++ b/third_party/tcmalloc/chromium/src/windows/patch_functions.cc @@ -122,6 +122,11 @@ const char kMangledDeleteArrayNothrow[] = "??_V@YAXPAXABUnothrow_t@std@@@Z"; extern "C" PERFTOOLS_DLL_DECL void _tcmalloc(); void _tcmalloc() { } +// This is the version needed for windows x64, which has a different +// decoration scheme which doesn't auto-add a leading underscore. +extern "C" PERFTOOLS_DLL_DECL void __tcmalloc(); +void __tcmalloc() { } + namespace { // most everything here is in an unnamed namespace typedef void (*GenericFnPtr)(); @@ -175,7 +180,7 @@ class LibcInfo { kNew, kNewArray, kDelete, kDeleteArray, kNewNothrow, kNewArrayNothrow, kDeleteNothrow, kDeleteArrayNothrow, // These are windows-only functions from malloc.h - k_Msize, k_Expand, k_Aligned_malloc, k_Aligned_free, + k_Msize, k_Expand, kNumFunctions }; @@ -274,12 +279,12 @@ template<int> class LibcInfoWithPatchFunctions : public LibcInfo { const std::nothrow_t&) __THROW; static size_t Perftools__msize(void *ptr) __THROW; static void* Perftools__expand(void *ptr, size_t size) __THROW; - static void* Perftools__aligned_malloc(size_t size, size_t alignment) __THROW; - static void Perftools__aligned_free(void *ptr) __THROW; // malloc.h also defines these functions: + // _aligned_malloc, _aligned_free, // _recalloc, _aligned_offset_malloc, _aligned_realloc, _aligned_recalloc // _aligned_offset_realloc, _aligned_offset_recalloc, _malloca, _freea // But they seem pretty obscure, and I'm fine not overriding them for now. + // It may be they all call into malloc/free anyway. }; // This is a subset of MODDULEENTRY32, that we need for patching. @@ -300,10 +305,19 @@ struct ModuleEntryCopy { ModuleEntryCopy(const MODULEINFO& mi) { this->modBaseAddr = mi.lpBaseOfDll; this->modBaseSize = mi.SizeOfImage; - for (int i = 0; i < sizeof(rgProcAddresses)/sizeof(*rgProcAddresses); i++) - rgProcAddresses[i] = (GenericFnPtr)::GetProcAddress( + LPVOID modEndAddr = (char*)mi.lpBaseOfDll + mi.SizeOfImage; + for (int i = 0; i < sizeof(rgProcAddresses)/sizeof(*rgProcAddresses); i++) { + FARPROC target = ::GetProcAddress( reinterpret_cast<const HMODULE>(mi.lpBaseOfDll), LibcInfo::function_name(i)); + // Sometimes a DLL forwards a function to a function in another + // DLL. We don't want to patch those forwarded functions -- + // they'll get patched when the other DLL is processed. + if (target >= modBaseAddr && target < modEndAddr) + rgProcAddresses[i] = (GenericFnPtr)target; + else + rgProcAddresses[i] = (GenericFnPtr)NULL; + } } }; @@ -390,7 +404,7 @@ const char* const LibcInfo::function_name_[] = { NULL, // kMangledNewArrayNothrow, NULL, // kMangledDeleteNothrow, NULL, // kMangledDeleteArrayNothrow, - "_msize", "_expand", "_aligned_malloc", "_aligned_free", + "_msize", "_expand", }; // For mingw, I can't patch the new/delete here, because the @@ -421,14 +435,6 @@ const GenericFnPtr LibcInfo::static_fn_[] = { #endif (GenericFnPtr)&::_msize, (GenericFnPtr)&::_expand, -#ifdef PERFTOOLS_NO_ALIGNED_MALLOC // for older versions of mingw - // _aligned_malloc isn't always available in mingw, so don't try to patch. - (GenericFnPtr)NULL, - (GenericFnPtr)NULL, -#else - (GenericFnPtr)&::_aligned_malloc, - (GenericFnPtr)&::_aligned_free, -#endif }; template<int T> GenericFnPtr LibcInfoWithPatchFunctions<T>::origstub_fn_[] = { @@ -451,8 +457,6 @@ const GenericFnPtr LibcInfoWithPatchFunctions<T>::perftools_fn_[] = { (GenericFnPtr)&Perftools_deletearray_nothrow, (GenericFnPtr)&Perftools__msize, (GenericFnPtr)&Perftools__expand, - (GenericFnPtr)&Perftools__aligned_malloc, - (GenericFnPtr)&Perftools__aligned_free, }; /*static*/ WindowsInfo::FunctionInfo WindowsInfo::function_info_[] = { @@ -908,21 +912,6 @@ void* LibcInfoWithPatchFunctions<T>::Perftools__expand(void *ptr, return NULL; } -template<int T> -void* LibcInfoWithPatchFunctions<T>::Perftools__aligned_malloc(size_t size, - size_t alignment) - __THROW { - void* result = do_memalign_or_cpp_memalign(alignment, size); - MallocHook::InvokeNewHook(result, size); - return result; -} - -template<int T> -void LibcInfoWithPatchFunctions<T>::Perftools__aligned_free(void *ptr) __THROW { - MallocHook::InvokeDeleteHook(ptr); - do_free_with_callback(ptr, (void (*)(void*))origstub_fn_[k_Aligned_free]); -} - LPVOID WINAPI WindowsInfo::Perftools_HeapAlloc(HANDLE hHeap, DWORD dwFlags, DWORD_PTR dwBytes) { LPVOID result = ((LPVOID (WINAPI *)(HANDLE, DWORD, DWORD_PTR)) diff --git a/third_party/tcmalloc/chromium/src/windows/port.cc b/third_party/tcmalloc/chromium/src/windows/port.cc index 59b0417..e77468c 100644 --- a/third_party/tcmalloc/chromium/src/windows/port.cc +++ b/third_party/tcmalloc/chromium/src/windows/port.cc @@ -35,6 +35,7 @@ # error You should only be including windows/port.cc in a windows environment! #endif +#define NOMINMAX // so std::max, below, compiles correctly #include <config.h> #include <string.h> // for strlen(), memset(), memcmp() #include <assert.h> @@ -43,29 +44,12 @@ #include "port.h" #include "base/logging.h" #include "base/spinlock.h" +#include "internal_logging.h" #include "system-alloc.h" // ----------------------------------------------------------------------- // 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) { @@ -82,9 +66,22 @@ extern "C" PERFTOOLS_DLL_DECL void* __sbrk(std::ptrdiff_t increment) { return NULL; } +// We need to write to 'stderr' without having windows allocate memory. +// The safest way is via a low-level call like WriteConsoleA(). But +// even then we need to be sure to print in small bursts so as to not +// require memory allocation. +extern "C" PERFTOOLS_DLL_DECL void WriteToStderr(const char* buf, int len) { + // Looks like windows allocates for writes of >80 bytes + for (int i = 0; i < len; i += 80) { + write(STDERR_FILENO, buf + i, std::min(80, len - i)); + } +} + + // ----------------------------------------------------------------------- // 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; @@ -105,9 +102,15 @@ bool CheckIfKernelSupportsTLS() { // Force a reference to p_thread_callback_tcmalloc and p_process_term_tcmalloc // to prevent whole program optimization from discarding the variables. #ifdef _MSC_VER +#if defined(_M_IX86) #pragma comment(linker, "/INCLUDE:__tls_used") #pragma comment(linker, "/INCLUDE:_p_thread_callback_tcmalloc") #pragma comment(linker, "/INCLUDE:_p_process_term_tcmalloc") +#elif defined(_M_X64) +#pragma comment(linker, "/INCLUDE:_tls_used") +#pragma comment(linker, "/INCLUDE:p_thread_callback_tcmalloc") +#pragma comment(linker, "/INCLUDE:p_process_term_tcmalloc") +#endif #endif // When destr_fn eventually runs, it's supposed to take as its @@ -173,7 +176,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). @@ -187,10 +190,38 @@ 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 +// The current system allocator. Because we don't link with system-alloc.cc, +// we need to define our own. +SysAllocator* sys_alloc = NULL; + // This is mostly like MmapSysAllocator::Alloc, except it does these weird // munmap's in the middle of the page, which is forbidden in windows. extern void* TCMalloc_SystemAlloc(size_t size, size_t *actual_size, diff --git a/third_party/tcmalloc/chromium/src/windows/port.h b/third_party/tcmalloc/chromium/src/windows/port.h index 66745d1..0faba01 100644 --- a/third_party/tcmalloc/chromium/src/windows/port.h +++ b/third_party/tcmalloc/chromium/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 */ + +#if __STDC__ +typedef _off_t off_t; +#endif + +/* 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; + } +} -// 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 ) +inline int munmap(void *addr, size_t length) { + return VirtualFree(addr, 0, MEM_RELEASE) ? 0 : -1; +} +#endif /* HAVE_MMAP */ -#define munmap(start, length) (VirtualFree(start, 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; +} -// We could maybe use VirtualAlloc for sbrk as well, but no need -#define sbrk(increment) ( (void*)-1 ) // sbrk returns -1 on failure +/* ----------------------------------- STRING ROUTINES */ -// ----------------------------------- 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 -// 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) +#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,79 +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 -// ----------------------------------- SYSTEM/PROCESS -typedef int pid_t; -#define getpid _getpid -#define getppid() (0) +#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 -// 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) +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 */ + +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_ */ |