123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497 |
- // -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
- /* 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
- #ifndef WIN32_LEAN_AND_MEAN
- #define WIN32_LEAN_AND_MEAN /* We always want minimal includes */
- #endif
- #include <windows.h>
- #include <io.h> /* because we so often use open/close/etc */
- #include <direct.h> /* for _getcwd */
- #include <process.h> /* for _getpid */
- #include <limits.h> /* for PATH_MAX */
- #include <stdarg.h> /* for va_list */
- #include <stdio.h> /* need this to override stdio's (v)snprintf */
- #include <sys/types.h> /* for _off_t */
- #include <assert.h>
- #include <stdlib.h> /* for rand, srand, _strtoxxx */
- #if defined(_MSC_VER) && _MSC_VER >= 1900
- #define _TIMESPEC_DEFINED
- #include <time.h>
- #endif
- /*
- * 4018: signed/unsigned mismatch is common (and ok for signed_i < unsigned_i)
- * 4244: otherwise we get problems when subtracting 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()
- * 4146: internal_logging.cc intentionally negates an unsigned value
- */
- #ifdef _MSC_VER
- #pragma warning(disable:4018 4244 4288 4267 4290 4996 4146)
- #endif
- #ifndef __cplusplus
- /* MSVC does not support C99 */
- # if !defined(__STDC_VERSION__) || __STDC_VERSION__ < 199901L
- # ifdef _MSC_VER
- # define inline __inline
- # else
- # define inline static
- # endif
- # endif
- #endif
- #ifdef __cplusplus
- # define EXTERN_C extern "C"
- #else
- # define EXTERN_C extern
- #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 <types.h> doesn't include ssize_t by default? */
- #ifdef _MSC_VER
- typedef intptr_t ssize_t;
- #endif
- /* ----------------------------------- THREADS */
- #ifndef HAVE_PTHREAD /* not true for MSVC, but may be true for MSYS */
- 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 */
- inline pthread_t pthread_self(void) {
- return GetCurrentThreadId();
- }
- #ifdef __cplusplus
- inline bool pthread_equal(pthread_t left, pthread_t right) {
- return left == right;
- }
- /*
- * 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 GOOGLE_MAYBE_THREADS_H_ 1
- /* This replaces maybe_threads.{h,cc} */
- EXTERN_C pthread_key_t PthreadKeyCreate(void (*destr_fn)(void*)); /* port.cc */
- inline int perftools_pthread_key_create(pthread_key_t *pkey,
- void (*destructor)(void*)) {
- pthread_key_t key = PthreadKeyCreate(destructor);
- if (key != TLS_OUT_OF_INDEXES) {
- *(pkey) = key;
- return 0;
- } else {
- return GetLastError();
- }
- }
- inline void* perftools_pthread_getspecific(DWORD key) {
- DWORD err = GetLastError();
- void* rv = TlsGetValue(key);
- if (err) SetLastError(err);
- return rv;
- }
- inline int perftools_pthread_setspecific(pthread_key_t key, const void *value) {
- if (TlsSetValue(key, (LPVOID)value))
- return 0;
- else
- return GetLastError();
- }
- EXTERN_C int perftools_pthread_once(pthread_once_t *once_control,
- void (*init_routine)(void));
- #endif /* __cplusplus */
- inline void sched_yield(void) {
- Sleep(0);
- }
- #endif /* HAVE_PTHREAD */
- /*
- * __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)
- /*
- * This code is obsolete, but I keep it around in case we are ever in
- * an environment where we can't or don't want to use google spinlocks
- * (from base/spinlock.{h,cc}). In that case, uncommenting this out,
- * and removing spinlock.cc from the build, should be enough to revert
- * back to using native spinlocks.
- */
- #if 0
- // 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.
- // 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) {
- perftools_pthread_once(&initialize_token_, InitializeMutex);
- }
- // It's important SpinLock not have a destructor: otherwise we run
- // into problems when the main thread has exited, but other threads
- // are still running and try to access a main-thread spinlock. This
- // means we leak mutex_ (we should call DeleteCriticalSection()
- // here). However, I've verified that all SpinLocks used in
- // perftools have program-long scope anyway, so the leak is
- // perfectly fine. But be aware of this for the future!
- void Lock() {
- // You'd thionk this would be unnecessary, since we call
- // InitializeMutex() in our constructor. But sometimes Lock() can
- // be called before our constructor is! This can only happen in
- // global constructors, when this is a global. If we live in
- // bar.cc, and some global constructor in foo.cc calls a routine
- // in bar.cc that calls this->Lock(), then Lock() may well run
- // before our global constructor does. To protect against that,
- // we do this check. For SpinLock objects created after main()
- // has started, this pthread_once call will always be a noop.
- 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 // #ifdef __cplusplus
- // This keeps us from using base/spinlock.h's implementation of SpinLock.
- #define BASE_SPINLOCK_H_ 1
- #endif /* #if 0 */
- /* ----------------------------------- MMAP and other memory allocation */
- #ifndef HAVE_MMAP /* not true for MSVC, but may be true for msys */
- #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 */
- #if __STDC__ && !defined(__MINGW32__)
- typedef _off_t off_t;
- #endif
- /* VirtualAlloc only replaces for mmap when certain invariants are kept. */
- inline void *mmap(void *addr, size_t length, int prot, int flags,
- int fd, off_t offset) {
- if (addr == NULL && fd == -1 && offset == 0 &&
- prot == (PROT_READ|PROT_WRITE) && flags == (MAP_PRIVATE|MAP_ANONYMOUS)) {
- return VirtualAlloc(0, length, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
- } else {
- return NULL;
- }
- }
- inline int munmap(void *addr, size_t length) {
- return VirtualFree(addr, 0, MEM_RELEASE) ? 0 : -1;
- }
- #endif /* HAVE_MMAP */
- /* We could maybe use VirtualAlloc for sbrk as well, but no need */
- inline void *sbrk(intptr_t increment) {
- // sbrk returns -1 on failure
- return (void*)-1;
- }
- /* ----------------------------------- 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 (!)).
- */
- #if defined(_MSC_VER) && _MSC_VER >= 1400
- /* We can use safe CRT functions, which the required functionality */
- inline int perftools_vsnprintf(char *str, size_t size, const char *format,
- va_list ap) {
- return vsnprintf_s(str, size, _TRUNCATE, format, ap);
- }
- #else
- inline int perftools_vsnprintf(char *str, size_t size, const char *format,
- va_list ap) {
- if (size == 0) /* not even room for a \0? */
- return -1; /* not what C99 says to do, but what windows does */
- str[size-1] = '\0';
- return _vsnprintf(str, size-1, format, ap);
- }
- #endif
- #ifndef HAVE_SNPRINTF
- inline int snprintf(char *str, size_t size, const char *format, ...) {
- va_list ap;
- int r;
- va_start(ap, format);
- r = perftools_vsnprintf(str, size, format, ap);
- va_end(ap);
- return r;
- }
- #endif
- #define PRIx64 "I64x"
- #define SCNx64 "I64x"
- #define PRId64 "I64d"
- #define SCNd64 "I64d"
- #define PRIu64 "I64u"
- #ifdef _WIN64
- # define PRIuPTR "llu"
- # define PRIxPTR "llx"
- #else
- # define PRIuPTR "lu"
- # define PRIxPTR "lx"
- #endif
- /* ----------------------------------- FILE IO */
- #ifndef PATH_MAX
- #define PATH_MAX 1024
- #endif
- #ifndef __MINGW32__
- enum { STDIN_FILENO = 0, STDOUT_FILENO = 1, STDERR_FILENO = 2 };
- #endif
- #ifndef O_RDONLY
- #define O_RDONLY _O_RDONLY
- #endif
- #if __STDC__ && !defined(__MINGW32__)
- /* These functions are considered non-standard */
- inline int access(const char *pathname, int mode) {
- return _access(pathname, mode);
- }
- inline int open(const char *pathname, int flags, int mode = 0) {
- return _open(pathname, flags, mode);
- }
- inline int close(int fd) {
- return _close(fd);
- }
- inline ssize_t read(int fd, void *buf, size_t count) {
- return _read(fd, buf, count);
- }
- inline ssize_t write(int fd, const void *buf, size_t count) {
- return _write(fd, buf, count);
- }
- inline off_t lseek(int fd, off_t offset, int whence) {
- return _lseek(fd, offset, whence);
- }
- inline char *getcwd(char *buf, size_t size) {
- return _getcwd(buf, size);
- }
- inline int mkdir(const char *pathname, int) {
- return _mkdir(pathname);
- }
- inline FILE *popen(const char *command, const char *type) {
- return _popen(command, type);
- }
- inline int pclose(FILE *stream) {
- return _pclose(stream);
- }
- #endif
- EXTERN_C PERFTOOLS_DLL_DECL void WriteToStderr(const char* buf, int len);
- /* ----------------------------------- SYSTEM/PROCESS */
- #ifndef HAVE_PID_T
- typedef int pid_t;
- #endif
- #if __STDC__ && !defined(__MINGW32__)
- inline pid_t getpid(void) { return _getpid(); }
- #endif
- inline pid_t getppid(void) { return 0; }
- /* Handle case when poll is used to simulate sleep. */
- inline int poll(struct pollfd* fds, int nfds, int timeout) {
- assert(fds == NULL);
- assert(nfds == 0);
- Sleep(timeout);
- return 0;
- }
- EXTERN_C PERFTOOLS_DLL_DECL int getpagesize(); /* in port.cc */
- /* ----------------------------------- OTHER */
- inline void srandom(unsigned int seed) { srand(seed); }
- inline long random(void) { return rand(); }
- #ifndef HAVE_DECL_SLEEP
- #define HAVE_DECL_SLEEP 0
- #endif
- #if !HAVE_DECL_SLEEP
- inline unsigned int sleep(unsigned int seconds) {
- Sleep(seconds * 1000);
- return 0;
- }
- #endif
- // mingw64 seems to define timespec (though mingw.org mingw doesn't),
- // protected by the _TIMESPEC_DEFINED macro.
- #ifndef _TIMESPEC_DEFINED
- struct timespec {
- int tv_sec;
- int tv_nsec;
- };
- #endif
- #ifndef HAVE_DECL_NANOSLEEP
- #define HAVE_DECL_NANOSLEEP 0
- #endif
- // latest mingw64 has nanosleep. Earlier mingw and MSVC do not
- #if !HAVE_DECL_NANOSLEEP
- inline int nanosleep(const struct timespec *req, struct timespec *rem) {
- Sleep(req->tv_sec * 1000 + req->tv_nsec / 1000000);
- return 0;
- }
- #endif
- #ifndef __MINGW32__
- #if defined(_MSC_VER) && _MSC_VER < 1800
- inline long long int strtoll(const char *nptr, char **endptr, int base) {
- return _strtoi64(nptr, endptr, base);
- }
- inline unsigned long long int strtoull(const char *nptr, char **endptr,
- int base) {
- return _strtoui64(nptr, endptr, base);
- }
- inline long long int strtoq(const char *nptr, char **endptr, int base) {
- return _strtoi64(nptr, endptr, base);
- }
- #endif
- inline unsigned long long int strtouq(const char *nptr, char **endptr,
- int base) {
- return _strtoui64(nptr, endptr, base);
- }
- inline long long atoll(const char *nptr) {
- return _atoi64(nptr);
- }
- #endif
- #define __THROW throw()
- /* ----------------------------------- TCMALLOC-SPECIFIC */
- /* tcmalloc.cc calls this so we can patch VirtualAlloc() et al. */
- extern void PatchWindowsFunctions();
- #endif /* _WIN32 */
- #undef inline
- #undef EXTERN_C
- #endif /* GOOGLE_BASE_WINDOWS_H_ */
|