15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* Copyright (c) 2007, Google Inc.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * All rights reserved.
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Redistribution and use in source and binary forms, with or without
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * modification, are permitted provided that the following conditions are
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * met:
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *     * Redistributions of source code must retain the above copyright
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * notice, this list of conditions and the following disclaimer.
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *     * Redistributions in binary form must reproduce the above
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * copyright notice, this list of conditions and the following disclaimer
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * in the documentation and/or other materials provided with the
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * distribution.
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *     * Neither the name of Google Inc. nor the names of its
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * contributors may be used to endorse or promote products derived from
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * this software without specific prior written permission.
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * ---
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Author: Craig Silverstein
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifndef _WIN32
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# error You should only be including windows/port.cc in a windows environment!
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define NOMINMAX       // so std::max, below, compiles correctly
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <config.h>
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <string.h>    // for strlen(), memset(), memcmp()
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <assert.h>
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <stdarg.h>    // for va_list, va_start, va_end
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <windows.h>
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "port.h"
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/logging.h"
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/spinlock.h"
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "internal_logging.h"
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "system-alloc.h"
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// -----------------------------------------------------------------------
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Basic libraries
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int getpagesize() {
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static int pagesize = 0;
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (pagesize == 0) {
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SYSTEM_INFO system_info;
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    GetSystemInfo(&system_info);
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pagesize = std::max(system_info.dwPageSize,
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        system_info.dwAllocationGranularity);
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return pagesize;
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)extern "C" PERFTOOLS_DLL_DECL void* __sbrk(ptrdiff_t increment) {
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  LOG(FATAL, "Windows doesn't implement sbrk!\n");
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return NULL;
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// We need to write to 'stderr' without having windows allocate memory.
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// The safest way is via a low-level call like WriteConsoleA().  But
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// even then we need to be sure to print in small bursts so as to not
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// require memory allocation.
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)extern "C" PERFTOOLS_DLL_DECL void WriteToStderr(const char* buf, int len) {
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Looks like windows allocates for writes of >80 bytes
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (int i = 0; i < len; i += 80) {
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    write(STDERR_FILENO, buf + i, std::min(80, len - i));
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// -----------------------------------------------------------------------
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Threads code
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Declared (not extern "C") in thread_cache.h
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool CheckIfKernelSupportsTLS() {
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // TODO(csilvers): return true (all win's since win95, at least, support this)
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return false;
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Windows doesn't support pthread_key_create's destr_function, and in
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// fact it's a bit tricky to get code to run when a thread exits.  This
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// is cargo-cult magic from http://www.codeproject.com/threads/tls.asp.
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// This code is for VC++ 7.1 and later; VC++ 6.0 support is possible
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// but more busy-work -- see the webpage for how to do it.  If all
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// this fails, we could use DllMain instead.  The big problem with
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// DllMain is it doesn't run if this code is statically linked into a
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// binary (it also doesn't run if the thread is terminated via
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// TerminateThread, which if we're lucky this routine does).
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Force a reference to _tls_used to make the linker create the TLS directory
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// if it's not already there (that is, even if __declspec(thread) is not used).
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Force a reference to p_thread_callback_tcmalloc and p_process_term_tcmalloc
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// to prevent whole program optimization from discarding the variables.
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifdef _MSC_VER
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(_M_IX86)
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#pragma comment(linker, "/INCLUDE:__tls_used")
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#pragma comment(linker, "/INCLUDE:_p_thread_callback_tcmalloc")
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#pragma comment(linker, "/INCLUDE:_p_process_term_tcmalloc")
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#elif defined(_M_X64)
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#pragma comment(linker, "/INCLUDE:_tls_used")
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#pragma comment(linker, "/INCLUDE:p_thread_callback_tcmalloc")
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#pragma comment(linker, "/INCLUDE:p_process_term_tcmalloc")
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// When destr_fn eventually runs, it's supposed to take as its
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// argument the tls-value associated with key that pthread_key_create
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// creates.  (Yeah, it sounds confusing but it's really not.)  We
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// store the destr_fn/key pair in this data structure.  Because we
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// store this in a single var, this implies we can only have one
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// destr_fn in a program!  That's enough in practice.  If asserts
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// trigger because we end up needing more, we'll have to turn this
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// into an array.
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)struct DestrFnClosure {
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void (*destr_fn)(void*);
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pthread_key_t key_for_destr_fn_arg;
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static DestrFnClosure destr_fn_info;   // initted to all NULL/0.
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int on_process_term(void) {
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (destr_fn_info.destr_fn) {
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    void *ptr = TlsGetValue(destr_fn_info.key_for_destr_fn_arg);
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // This shouldn't be necessary, but in Release mode, Windows
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // sometimes trashes the pointer in the TLS slot, so we need to
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // remove the pointer from the TLS slot before the thread dies.
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    TlsSetValue(destr_fn_info.key_for_destr_fn_arg, NULL);
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (ptr)  // pthread semantics say not to call if ptr is NULL
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      (*destr_fn_info.destr_fn)(ptr);
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return 0;
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void NTAPI on_tls_callback(HINSTANCE h, DWORD dwReason, PVOID pv) {
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (dwReason == DLL_THREAD_DETACH) {   // thread is being destroyed!
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    on_process_term();
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifdef _MSC_VER
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// extern "C" suppresses C++ name mangling so we know the symbol names
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// for the linker /INCLUDE:symbol pragmas above.
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)extern "C" {
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// This tells the linker to run these functions.
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#pragma data_seg(push, old_seg)
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#pragma data_seg(".CRT$XLB")
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void (NTAPI *p_thread_callback_tcmalloc)(
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    HINSTANCE h, DWORD dwReason, PVOID pv) = on_tls_callback;
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#pragma data_seg(".CRT$XTU")
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int (*p_process_term_tcmalloc)(void) = on_process_term;
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#pragma data_seg(pop, old_seg)
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // extern "C"
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#else  // #ifdef _MSC_VER  [probably msys/mingw]
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// We have to try the DllMain solution here, because we can't use the
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// msvc-specific pragmas.
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)BOOL WINAPI DllMain(HINSTANCE h, DWORD dwReason, PVOID pv) {
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (dwReason == DLL_THREAD_DETACH)
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    on_tls_callback(h, dwReason, pv);
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  else if (dwReason == DLL_PROCESS_DETACH)
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    on_process_term();
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return TRUE;
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif  // #ifdef _MSC_VER
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)extern "C" pthread_key_t PthreadKeyCreate(void (*destr_fn)(void*)) {
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Semantics are: we create a new key, and then promise to call
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // destr_fn with TlsGetValue(key) when the thread is destroyed
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // (as long as TlsGetValue(key) is not NULL).
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pthread_key_t key = TlsAlloc();
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (destr_fn) {   // register it
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // If this assert fails, we'll need to support an array of destr_fn_infos
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    assert(destr_fn_info.destr_fn == NULL);
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    destr_fn_info.destr_fn = destr_fn;
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    destr_fn_info.key_for_destr_fn_arg = key;
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return key;
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// NOTE: this is Win2K and later.  For Win98 we could use a CRITICAL_SECTION...
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)extern "C" int perftools_pthread_once(pthread_once_t *once_control,
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                      void (*init_routine)(void)) {
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Try for a fast path first. Note: this should be an acquire semantics read.
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // It is on x86 and x64, where Windows runs.
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (*once_control != 1) {
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    while (true) {
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      switch (InterlockedCompareExchange(once_control, 2, 0)) {
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        case 0:
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          init_routine();
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          InterlockedExchange(once_control, 1);
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          return 0;
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        case 1:
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          // The initializer has already been executed
2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          return 0;
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        default:
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          // The initializer is being processed by another thread
2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          SwitchToThread();
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return 0;
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// -----------------------------------------------------------------------
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// These functions replace system-alloc.cc
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// This is mostly like MmapSysAllocator::Alloc, except it does these weird
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// munmap's in the middle of the page, which is forbidden in windows.
2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)extern void* TCMalloc_SystemAlloc(size_t size, size_t *actual_size,
2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                  size_t alignment) {
2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Align on the pagesize boundary
2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const int pagesize = getpagesize();
2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (alignment < pagesize) alignment = pagesize;
2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  size = ((size + alignment - 1) / alignment) * alignment;
2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Safest is to make actual_size same as input-size.
2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (actual_size) {
2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    *actual_size = size;
2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Ask for extra memory if alignment > pagesize
2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  size_t extra = 0;
2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (alignment > pagesize) {
2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    extra = alignment - pagesize;
2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void* result = VirtualAlloc(0, size + extra,
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              MEM_COMMIT|MEM_RESERVE, PAGE_READWRITE);
2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (result == NULL)
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return NULL;
2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Adjust the return memory so it is aligned
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  uintptr_t ptr = reinterpret_cast<uintptr_t>(result);
2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  size_t adjust = 0;
2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if ((ptr & (alignment - 1)) != 0) {
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    adjust = alignment - (ptr & (alignment - 1));
2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ptr += adjust;
2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return reinterpret_cast<void*>(ptr);
2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void TCMalloc_SystemRelease(void* start, size_t length) {
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // TODO(csilvers): should I be calling VirtualFree here?
2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool RegisterSystemAllocator(SysAllocator *allocator, int priority) {
2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return false;   // we don't allow registration on windows, right now
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void DumpSystemAllocatorStats(TCMalloc_Printer* printer) {
2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We don't dump stats on windows, right now
2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// The current system allocator
2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SysAllocator* sys_alloc = NULL;
2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// -----------------------------------------------------------------------
2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// These functions rework existing functions of the same name in the
2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Google codebase.
2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// A replacement for HeapProfiler::CleanupOldProfiles.
2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void DeleteMatchingFiles(const char* prefix, const char* full_glob) {
2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  WIN32_FIND_DATAA found;  // that final A is for Ansi (as opposed to Unicode)
2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  HANDLE hFind = FindFirstFileA(full_glob, &found);   // A is for Ansi
2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (hFind != INVALID_HANDLE_VALUE) {
2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const int prefix_length = strlen(prefix);
2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    do {
2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      const char *fname = found.cFileName;
2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if ((strlen(fname) >= prefix_length) &&
2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          (memcmp(fname, prefix, prefix_length) == 0)) {
2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        RAW_VLOG(0, "Removing old heap profile %s\n", fname);
2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // TODO(csilvers): we really need to unlink dirname + fname
2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        _unlink(fname);
2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } while (FindNextFileA(hFind, &found) != FALSE);  // A is for Ansi
2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    FindClose(hFind);
2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
295