| Index: third_party/tcmalloc/chromium/src/windows/port.cc
|
| ===================================================================
|
| --- third_party/tcmalloc/chromium/src/windows/port.cc (revision 88335)
|
| +++ third_party/tcmalloc/chromium/src/windows/port.cc (working copy)
|
| @@ -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 @@
|
| 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,10 +102,16 @@
|
| // 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
|
| // argument the tls-value associated with key that pthread_key_create
|
| @@ -173,7 +176,7 @@
|
|
|
| #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 @@
|
| 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,
|
|
|