1/* Copyright (c) 2007, Google Inc. 2 * All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions are 6 * met: 7 * 8 * * Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * * Redistributions in binary form must reproduce the above 11 * copyright notice, this list of conditions and the following disclaimer 12 * in the documentation and/or other materials provided with the 13 * distribution. 14 * * Neither the name of Google Inc. nor the names of its 15 * contributors may be used to endorse or promote products derived from 16 * this software without specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 * 30 * --- 31 * Author: Craig Silverstein 32 * 33 * These are some portability typedefs and defines to make it a bit 34 * easier to compile this code under VC++. 35 * 36 * Several of these are taken from glib: 37 * http://developer.gnome.org/doc/API/glib/glib-windows-compatability-functions.html 38 */ 39 40#ifndef GOOGLE_BASE_WINDOWS_H_ 41#define GOOGLE_BASE_WINDOWS_H_ 42 43/* You should never include this file directly, but always include it 44 from either config.h (MSVC) or mingw.h (MinGW/msys). */ 45#if !defined(GOOGLE_PERFTOOLS_WINDOWS_CONFIG_H_) && \ 46 !defined(GOOGLE_PERFTOOLS_WINDOWS_MINGW_H_) 47# error "port.h should only be included from config.h or mingw.h" 48#endif 49 50#ifdef _WIN32 51 52#ifndef NOMINMAX 53#define NOMINMAX /* Do not define min and max macros. */ 54#endif 55#ifndef WIN32_LEAN_AND_MEAN 56#define WIN32_LEAN_AND_MEAN /* We always want minimal includes */ 57#endif 58#include <windows.h> 59#include <io.h> /* because we so often use open/close/etc */ 60#include <direct.h> /* for _getcwd */ 61#include <process.h> /* for _getpid */ 62#include <limits.h> /* for PATH_MAX */ 63#include <stdarg.h> /* for va_list */ 64#include <stdio.h> /* need this to override stdio's (v)snprintf */ 65#include <sys/types.h> /* for _off_t */ 66#include <assert.h> 67#include <stdlib.h> /* for rand, srand, _strtoxxx */ 68 69/* 70 * 4018: signed/unsigned mismatch is common (and ok for signed_i < unsigned_i) 71 * 4244: otherwise we get problems when subtracting two size_t's to an int 72 * 4288: VC++7 gets confused when a var is defined in a loop and then after it 73 * 4267: too many false positives for "conversion gives possible data loss" 74 * 4290: it's ok windows ignores the "throw" directive 75 * 4996: Yes, we're ok using "unsafe" functions like vsnprintf and getenv() 76 * 4146: internal_logging.cc intentionally negates an unsigned value 77 */ 78#ifdef _MSC_VER 79#pragma warning(disable:4018 4244 4288 4267 4290 4996 4146) 80#endif 81 82#ifndef __cplusplus 83/* MSVC does not support C99 */ 84# if !defined(__STDC_VERSION__) || __STDC_VERSION__ < 199901L 85# ifdef _MSC_VER 86# define inline __inline 87# else 88# define inline static 89# endif 90# endif 91#endif 92 93#ifdef __cplusplus 94# define EXTERN_C extern "C" 95#else 96# define EXTERN_C extern 97#endif 98 99/* ----------------------------------- BASIC TYPES */ 100 101#ifndef HAVE_STDINT_H 102#ifndef HAVE___INT64 /* we need to have all the __intX names */ 103# error Do not know how to set up type aliases. Edit port.h for your system. 104#endif 105 106typedef __int8 int8_t; 107typedef __int16 int16_t; 108typedef __int32 int32_t; 109typedef __int64 int64_t; 110typedef unsigned __int8 uint8_t; 111typedef unsigned __int16 uint16_t; 112typedef unsigned __int32 uint32_t; 113typedef unsigned __int64 uint64_t; 114#endif /* #ifndef HAVE_STDINT_H */ 115 116/* I guess MSVC's <types.h> doesn't include ssize_t by default? */ 117#ifdef _MSC_VER 118typedef intptr_t ssize_t; 119#endif 120 121/* ----------------------------------- THREADS */ 122 123#ifndef HAVE_PTHREAD /* not true for MSVC, but may be true for MSYS */ 124typedef DWORD pthread_t; 125typedef DWORD pthread_key_t; 126typedef LONG pthread_once_t; 127enum { PTHREAD_ONCE_INIT = 0 }; /* important that this be 0! for SpinLock */ 128 129inline pthread_t pthread_self(void) { 130 return GetCurrentThreadId(); 131} 132 133#ifdef __cplusplus 134inline bool pthread_equal(pthread_t left, pthread_t right) { 135 return left == right; 136} 137 138/* This replaces maybe_threads.{h,cc} */ 139EXTERN_C pthread_key_t PthreadKeyCreate(void (*destr_fn)(void*)); /* port.cc */ 140 141inline int perftools_pthread_key_create(pthread_key_t *pkey, 142 void (*destructor)(void*)) { 143 pthread_key_t key = PthreadKeyCreate(destructor); 144 if (key != TLS_OUT_OF_INDEXES) { 145 *(pkey) = key; 146 return 0; 147 } else { 148 return GetLastError(); 149 } 150} 151 152inline void* perftools_pthread_getspecific(DWORD key) { 153 DWORD err = GetLastError(); 154 void* rv = TlsGetValue(key); 155 if (err) SetLastError(err); 156 return rv; 157} 158 159inline int perftools_pthread_setspecific(pthread_key_t key, const void *value) { 160 if (TlsSetValue(key, (LPVOID)value)) 161 return 0; 162 else 163 return GetLastError(); 164} 165 166EXTERN_C int perftools_pthread_once(pthread_once_t *once_control, 167 void (*init_routine)(void)); 168 169#endif /* __cplusplus */ 170#endif /* HAVE_PTHREAD */ 171 172inline void sched_yield(void) { 173 Sleep(0); 174} 175 176/* 177 * __declspec(thread) isn't usable in a dll opened via LoadLibrary(). 178 * But it doesn't work to LoadLibrary() us anyway, because of all the 179 * things we need to do before main()! So this kind of TLS is safe for us. 180 */ 181#define __thread __declspec(thread) 182 183/* 184 * This code is obsolete, but I keep it around in case we are ever in 185 * an environment where we can't or don't want to use google spinlocks 186 * (from base/spinlock.{h,cc}). In that case, uncommenting this out, 187 * and removing spinlock.cc from the build, should be enough to revert 188 * back to using native spinlocks. 189 */ 190#if 0 191// Windows uses a spinlock internally for its mutexes, making our life easy! 192// However, the Windows spinlock must always be initialized, making life hard, 193// since we want LINKER_INITIALIZED. We work around this by having the 194// linker initialize a bool to 0, and check that before accessing the mutex. 195// This replaces spinlock.{h,cc}, and all the stuff it depends on (atomicops) 196#ifdef __cplusplus 197class SpinLock { 198 public: 199 SpinLock() : initialize_token_(PTHREAD_ONCE_INIT) {} 200 // Used for global SpinLock vars (see base/spinlock.h for more details). 201 enum StaticInitializer { LINKER_INITIALIZED }; 202 explicit SpinLock(StaticInitializer) : initialize_token_(PTHREAD_ONCE_INIT) { 203 perftools_pthread_once(&initialize_token_, InitializeMutex); 204 } 205 206 // It's important SpinLock not have a destructor: otherwise we run 207 // into problems when the main thread has exited, but other threads 208 // are still running and try to access a main-thread spinlock. This 209 // means we leak mutex_ (we should call DeleteCriticalSection() 210 // here). However, I've verified that all SpinLocks used in 211 // perftools have program-long scope anyway, so the leak is 212 // perfectly fine. But be aware of this for the future! 213 214 void Lock() { 215 // You'd thionk this would be unnecessary, since we call 216 // InitializeMutex() in our constructor. But sometimes Lock() can 217 // be called before our constructor is! This can only happen in 218 // global constructors, when this is a global. If we live in 219 // bar.cc, and some global constructor in foo.cc calls a routine 220 // in bar.cc that calls this->Lock(), then Lock() may well run 221 // before our global constructor does. To protect against that, 222 // we do this check. For SpinLock objects created after main() 223 // has started, this pthread_once call will always be a noop. 224 perftools_pthread_once(&initialize_token_, InitializeMutex); 225 EnterCriticalSection(&mutex_); 226 } 227 void Unlock() { 228 LeaveCriticalSection(&mutex_); 229 } 230 231 // Used in assertion checks: assert(lock.IsHeld()) (see base/spinlock.h). 232 inline bool IsHeld() const { 233 // This works, but probes undocumented internals, so I've commented it out. 234 // c.f. http://msdn.microsoft.com/msdnmag/issues/03/12/CriticalSections/ 235 //return mutex_.LockCount>=0 && mutex_.OwningThread==GetCurrentThreadId(); 236 return true; 237 } 238 private: 239 void InitializeMutex() { InitializeCriticalSection(&mutex_); } 240 241 pthread_once_t initialize_token_; 242 CRITICAL_SECTION mutex_; 243}; 244 245class SpinLockHolder { // Acquires a spinlock for as long as the scope lasts 246 private: 247 SpinLock* lock_; 248 public: 249 inline explicit SpinLockHolder(SpinLock* l) : lock_(l) { l->Lock(); } 250 inline ~SpinLockHolder() { lock_->Unlock(); } 251}; 252#endif // #ifdef __cplusplus 253 254// This keeps us from using base/spinlock.h's implementation of SpinLock. 255#define BASE_SPINLOCK_H_ 1 256 257#endif /* #if 0 */ 258 259/* ----------------------------------- MMAP and other memory allocation */ 260 261#ifndef HAVE_MMAP /* not true for MSVC, but may be true for msys */ 262#define MAP_FAILED 0 263#define MREMAP_FIXED 2 /* the value in linux, though it doesn't really matter */ 264/* These, when combined with the mmap invariants below, yield the proper action */ 265#define PROT_READ PAGE_READWRITE 266#define PROT_WRITE PAGE_READWRITE 267#define MAP_ANONYMOUS MEM_RESERVE 268#define MAP_PRIVATE MEM_COMMIT 269#define MAP_SHARED MEM_RESERVE /* value of this #define is 100% arbitrary */ 270 271#if __STDC__ && !defined(__MINGW32__) 272typedef _off_t off_t; 273#endif 274 275/* VirtualAlloc only replaces for mmap when certain invariants are kept. */ 276inline void *mmap(void *addr, size_t length, int prot, int flags, 277 int fd, off_t offset) { 278 if (addr == NULL && fd == -1 && offset == 0 && 279 prot == (PROT_READ|PROT_WRITE) && flags == (MAP_PRIVATE|MAP_ANONYMOUS)) { 280 return VirtualAlloc(0, length, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); 281 } else { 282 return NULL; 283 } 284} 285 286inline int munmap(void *addr, size_t length) { 287 return VirtualFree(addr, 0, MEM_RELEASE) ? 0 : -1; 288} 289#endif /* HAVE_MMAP */ 290 291/* We could maybe use VirtualAlloc for sbrk as well, but no need */ 292inline void *sbrk(intptr_t increment) { 293 // sbrk returns -1 on failure 294 return (void*)-1; 295} 296 297 298/* ----------------------------------- STRING ROUTINES */ 299 300/* 301 * We can't just use _vsnprintf and _snprintf as drop-in-replacements, 302 * because they don't always NUL-terminate. :-( We also can't use the 303 * name vsnprintf, since windows defines that (but not snprintf (!)). 304 */ 305#if defined(_MSC_VER) && _MSC_VER >= 1400 306/* We can use safe CRT functions, which the required functionality */ 307inline int perftools_vsnprintf(char *str, size_t size, const char *format, 308 va_list ap) { 309 return vsnprintf_s(str, size, _TRUNCATE, format, ap); 310} 311#else 312inline int perftools_vsnprintf(char *str, size_t size, const char *format, 313 va_list ap) { 314 if (size == 0) /* not even room for a \0? */ 315 return -1; /* not what C99 says to do, but what windows does */ 316 str[size-1] = '\0'; 317 return _vsnprintf(str, size-1, format, ap); 318} 319#endif 320 321#ifndef HAVE_SNPRINTF 322inline int snprintf(char *str, size_t size, const char *format, ...) { 323 va_list ap; 324 int r; 325 va_start(ap, format); 326 r = perftools_vsnprintf(str, size, format, ap); 327 va_end(ap); 328 return r; 329} 330#endif 331 332#define PRIx64 "I64x" 333#define SCNx64 "I64x" 334#define PRId64 "I64d" 335#define SCNd64 "I64d" 336#define PRIu64 "I64u" 337#ifdef _WIN64 338# define PRIuPTR "llu" 339# define PRIxPTR "llx" 340#else 341# define PRIuPTR "lu" 342# define PRIxPTR "lx" 343#endif 344 345/* ----------------------------------- FILE IO */ 346 347#ifndef PATH_MAX 348#define PATH_MAX 1024 349#endif 350#ifndef __MINGW32__ 351enum { STDIN_FILENO = 0, STDOUT_FILENO = 1, STDERR_FILENO = 2 }; 352#endif 353#ifndef O_RDONLY 354#define O_RDONLY _O_RDONLY 355#endif 356 357#if __STDC__ && !defined(__MINGW32__) 358/* These functions are considered non-standard */ 359inline int access(const char *pathname, int mode) { 360 return _access(pathname, mode); 361} 362inline int open(const char *pathname, int flags, int mode = 0) { 363 return _open(pathname, flags, mode); 364} 365inline int close(int fd) { 366 return _close(fd); 367} 368inline ssize_t read(int fd, void *buf, size_t count) { 369 return _read(fd, buf, count); 370} 371inline ssize_t write(int fd, const void *buf, size_t count) { 372 return _write(fd, buf, count); 373} 374inline off_t lseek(int fd, off_t offset, int whence) { 375 return _lseek(fd, offset, whence); 376} 377inline char *getcwd(char *buf, size_t size) { 378 return _getcwd(buf, size); 379} 380inline int mkdir(const char *pathname, int) { 381 return _mkdir(pathname); 382} 383 384inline FILE *popen(const char *command, const char *type) { 385 return _popen(command, type); 386} 387inline int pclose(FILE *stream) { 388 return _pclose(stream); 389} 390#endif 391 392EXTERN_C PERFTOOLS_DLL_DECL void WriteToStderr(const char* buf, int len); 393 394/* ----------------------------------- SYSTEM/PROCESS */ 395 396typedef int pid_t; 397#if __STDC__ && !defined(__MINGW32__) 398inline pid_t getpid(void) { return _getpid(); } 399#endif 400inline pid_t getppid(void) { return 0; } 401 402/* Handle case when poll is used to simulate sleep. */ 403inline int poll(struct pollfd* fds, int nfds, int timeout) { 404 assert(fds == NULL); 405 assert(nfds == 0); 406 Sleep(timeout); 407 return 0; 408} 409 410EXTERN_C int getpagesize(); /* in port.cc */ 411 412/* ----------------------------------- OTHER */ 413 414inline void srandom(unsigned int seed) { srand(seed); } 415inline long random(void) { return rand(); } 416inline unsigned int sleep(unsigned int seconds) { 417 Sleep(seconds * 1000); 418 return 0; 419} 420 421// mingw64 seems to define timespec (though mingw.org mingw doesn't), 422// protected by the _TIMESPEC_DEFINED macro. 423#ifndef _TIMESPEC_DEFINED 424struct timespec { 425 int tv_sec; 426 int tv_nsec; 427}; 428#endif 429 430inline int nanosleep(const struct timespec *req, struct timespec *rem) { 431 Sleep(req->tv_sec * 1000 + req->tv_nsec / 1000000); 432 return 0; 433} 434 435#ifndef __MINGW32__ 436#if _MSC_VER < 1800 // Not required >= VS2013. 437inline long long int strtoll(const char *nptr, char **endptr, int base) { 438 return _strtoi64(nptr, endptr, base); 439} 440inline unsigned long long int strtoull(const char *nptr, char **endptr, 441 int base) { 442 return _strtoui64(nptr, endptr, base); 443} 444inline long long int strtoq(const char *nptr, char **endptr, int base) { 445 return _strtoi64(nptr, endptr, base); 446} 447#endif 448inline unsigned long long int strtouq(const char *nptr, char **endptr, 449 int base) { 450 return _strtoui64(nptr, endptr, base); 451} 452inline long long atoll(const char *nptr) { 453 return _atoi64(nptr); 454} 455#endif 456 457#define __THROW throw() 458 459/* ----------------------------------- TCMALLOC-SPECIFIC */ 460 461/* tcmalloc.cc calls this so we can patch VirtualAlloc() et al. */ 462extern void PatchWindowsFunctions(); 463 464// ----------------------------------- BUILD-SPECIFIC 465 466/* 467 * windows/port.h defines compatibility APIs for several .h files, which 468 * we therefore shouldn't be #including directly. This hack keeps us from 469 * doing so. TODO(csilvers): do something more principled. 470 */ 471#define GOOGLE_MAYBE_THREADS_H_ 1 472 473 474#endif /* _WIN32 */ 475 476#undef inline 477#undef EXTERN_C 478 479#endif /* GOOGLE_BASE_WINDOWS_H_ */ 480