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