Home | History | Annotate | Download | only in windows
      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 
    106 typedef __int8 int8_t;
    107 typedef __int16 int16_t;
    108 typedef __int32 int32_t;
    109 typedef __int64 int64_t;
    110 typedef unsigned __int8 uint8_t;
    111 typedef unsigned __int16 uint16_t;
    112 typedef unsigned __int32 uint32_t;
    113 typedef 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
    118 typedef intptr_t ssize_t;
    119 #endif
    120 
    121 /* ----------------------------------- THREADS */
    122 
    123 #ifndef HAVE_PTHREAD   /* not true for MSVC, but may be true for MSYS */
    124 typedef DWORD pthread_t;
    125 typedef DWORD pthread_key_t;
    126 typedef LONG pthread_once_t;
    127 enum { PTHREAD_ONCE_INIT = 0 };   /* important that this be 0! for SpinLock */
    128 
    129 inline pthread_t pthread_self(void) {
    130   return GetCurrentThreadId();
    131 }
    132 
    133 #ifdef __cplusplus
    134 inline bool pthread_equal(pthread_t left, pthread_t right) {
    135   return left == right;
    136 }
    137 
    138 /* This replaces maybe_threads.{h,cc} */
    139 EXTERN_C pthread_key_t PthreadKeyCreate(void (*destr_fn)(void*));  /* port.cc */
    140 
    141 inline 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 
    152 inline 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 
    159 inline 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 
    166 EXTERN_C int perftools_pthread_once(pthread_once_t *once_control,
    167                                     void (*init_routine)(void));
    168 
    169 #endif  /* __cplusplus */
    170 #endif  /* HAVE_PTHREAD */
    171 
    172 inline 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
    197 class 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 
    245 class 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__)
    272 typedef _off_t off_t;
    273 #endif
    274 
    275 /* VirtualAlloc only replaces for mmap when certain invariants are kept. */
    276 inline 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 
    286 inline 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 */
    292 inline 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 */
    307 inline 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
    312 inline 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
    322 inline 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__
    351 enum { 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 */
    359 inline int access(const char *pathname, int mode) {
    360   return _access(pathname, mode);
    361 }
    362 inline int open(const char *pathname, int flags, int mode = 0) {
    363   return _open(pathname, flags, mode);
    364 }
    365 inline int close(int fd) {
    366   return _close(fd);
    367 }
    368 inline ssize_t read(int fd, void *buf, size_t count) {
    369   return _read(fd, buf, count);
    370 }
    371 inline ssize_t write(int fd, const void *buf, size_t count) {
    372   return _write(fd, buf, count);
    373 }
    374 inline off_t lseek(int fd, off_t offset, int whence) {
    375   return _lseek(fd, offset, whence);
    376 }
    377 inline char *getcwd(char *buf, size_t size) {
    378   return _getcwd(buf, size);
    379 }
    380 inline int mkdir(const char *pathname, int) {
    381   return _mkdir(pathname);
    382 }
    383 
    384 inline FILE *popen(const char *command, const char *type) {
    385   return _popen(command, type);
    386 }
    387 inline int pclose(FILE *stream) {
    388   return _pclose(stream);
    389 }
    390 #endif
    391 
    392 EXTERN_C PERFTOOLS_DLL_DECL void WriteToStderr(const char* buf, int len);
    393 
    394 /* ----------------------------------- SYSTEM/PROCESS */
    395 
    396 typedef int pid_t;
    397 #if __STDC__ && !defined(__MINGW32__)
    398 inline pid_t getpid(void) { return _getpid(); }
    399 #endif
    400 inline pid_t getppid(void) { return 0; }
    401 
    402 /* Handle case when poll is used to simulate sleep. */
    403 inline 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 
    410 EXTERN_C int getpagesize();   /* in port.cc */
    411 
    412 /* ----------------------------------- OTHER */
    413 
    414 inline void srandom(unsigned int seed) { srand(seed); }
    415 inline long random(void) { return rand(); }
    416 inline 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
    424 struct timespec {
    425   int tv_sec;
    426   int tv_nsec;
    427 };
    428 #endif
    429 
    430 inline 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.
    437 inline long long int strtoll(const char *nptr, char **endptr, int base) {
    438     return _strtoi64(nptr, endptr, base);
    439 }
    440 inline unsigned long long int strtoull(const char *nptr, char **endptr,
    441                                        int base) {
    442     return _strtoui64(nptr, endptr, base);
    443 }
    444 inline long long int strtoq(const char *nptr, char **endptr, int base) {
    445     return _strtoi64(nptr, endptr, base);
    446 }
    447 #endif
    448 inline unsigned long long int strtouq(const char *nptr, char **endptr,
    449                                       int base) {
    450     return _strtoui64(nptr, endptr, base);
    451 }
    452 inline 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. */
    462 extern 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