/* Copyright (c) 2007, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * --- * Author: Craig Silverstein * * These are some portability typedefs and defines to make it a bit * easier to compile this code under VC++. * * Several of these are taken from glib: * http://developer.gnome.org/doc/API/glib/glib-windows-compatability-functions.html */ #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). #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" #endif #ifdef WIN32 #define WIN32_LEAN_AND_MEAN /* We always want minimal includes */ #include #include /* because we so often use open/close/etc */ #include /* for va_list */ #include /* 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() #ifdef _MSC_VER #pragma warning(disable:4018 4244 4288 4267 4290 4996) #endif // ----------------------------------- BASIC TYPES #ifndef HAVE_STDINT_H #ifndef HAVE___INT64 /* we need to have all the __intX names */ # error Do not know how to set up type aliases. Edit port.h for your system. #endif typedef __int8 int8_t; typedef __int16 int16_t; typedef __int32 int32_t; typedef __int64 int64_t; 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 // I guess MSVC's doesn't include ssize_t by default? #ifdef _MSC_VER typedef intptr_t ssize_t; #endif // ----------------------------------- THREADS 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)) // 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) #define perftools_pthread_getspecific(key) \ TlsGetValue(key) #define perftools_pthread_setspecific(key, val) \ TlsSetValue((key), (val)) // NOTE: this is Win98 and later. For Win95 we could use a CRITICAL_SECTION... #define perftools_pthread_once(once, init) do { \ if (InterlockedCompareExchange(once, 1, 0) == 0) (init)(); \ } while (0) // __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) // Windows uses a spinlock internally for its mutexes, making our life easy! // However, the Windows spinlock must always be initialized, making life hard, // since we want LINKER_INITIALIZED. We work around this by having the // linker initialize a bool to 0, and check that before accessing the mutex. // TODO(csilvers): figure out a faster way. // This replaces spinlock.{h,cc}, and all the stuff it depends on (atomicops) #ifdef __cplusplus class SpinLock { public: SpinLock() : initialize_token_(PTHREAD_ONCE_INIT) {} // Used for global SpinLock vars (see base/spinlock.h for more details). enum StaticInitializer { LINKER_INITIALIZED }; explicit SpinLock(StaticInitializer) : initialize_token_(PTHREAD_ONCE_INIT) {} ~SpinLock() { perftools_pthread_once(&initialize_token_, InitializeMutex); DeleteCriticalSection(&mutex_); } void Lock() { perftools_pthread_once(&initialize_token_, InitializeMutex); EnterCriticalSection(&mutex_); } void Unlock() { LeaveCriticalSection(&mutex_); } // Used in assertion checks: assert(lock.IsHeld()) (see base/spinlock.h). inline bool IsHeld() const { // This works, but probes undocumented internals, so I've commented it out. // c.f. http://msdn.microsoft.com/msdnmag/issues/03/12/CriticalSections/ //return mutex_.LockCount>=0 && mutex_.OwningThread==GetCurrentThreadId(); return true; } private: void InitializeMutex() { InitializeCriticalSection(&mutex_); } pthread_once_t initialize_token_; CRITICAL_SECTION mutex_; }; class SpinLockHolder { // Acquires a spinlock for as long as the scope lasts private: SpinLock* lock_; public: inline explicit SpinLockHolder(SpinLock* l) : lock_(l) { l->Lock(); } inline ~SpinLockHolder() { lock_->Unlock(); } }; #endif // 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); // ----------------------------------- MMAP and other memory allocation #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 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 // 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 ) #define munmap(start, length) (VirtualFree(start, 0, MEM_RELEASE) ? 0 : -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 // 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) // ----------------------------------- 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) // ----------------------------------- SYSTEM/PROCESS typedef int pid_t; #define getpid _getpid extern PERFTOOLS_DLL_DECL int getpagesize(); // in port.cc // ----------------------------------- OTHER #define srandom srand #define random rand #define sleep(t) Sleep(t * 1000) #define __THROW throw() // ----------------------------------- TCMALLOC-SPECIFIC // By defining this, we get away without having to get a StackTrace // But maybe play around with ExperimentalGetStackTrace in port.cc #define NO_TCMALLOC_SAMPLES // tcmalloc.cc calls this so we can patch VirtualAlloc() et al. // TODO(csilvers): instead of patching the functions, consider just replacing // them. To do this, add the following post-build step the the .vcproj: // // libem.lib is a library you write that defines calloc, free, malloc, // realloc, _calloc_dbg, _free_dbg, _msize_dbg, _malloc_dbg, // _realloc_dbg, _CrtDumpMemoryLeaks, and _CrtSetDbgFlag (at least for // VC++ 7.1). The list of functions to override, and the name/location of // the files to remove, may differ between VC++ versions. extern PERFTOOLS_DLL_DECL void PatchWindowsFunctions(); extern PERFTOOLS_DLL_DECL void UnpatchWindowsFunctions(); // ----------------------------------- 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. #define BASE_SPINLOCK_H__ 1 #define GOOGLE_MAYBE_THREADS_H__ 1 #endif /* WIN32 */ #endif /* GOOGLE_BASE_WINDOWS_H__ */