diff options
Diffstat (limited to 'src/windows/port.h')
-rw-r--r-- | src/windows/port.h | 352 |
1 files changed, 239 insertions, 113 deletions
diff --git a/src/windows/port.h b/src/windows/port.h index ff6b714..0faba01 100644 --- a/src/windows/port.h +++ b/src/windows/port.h @@ -40,8 +40,8 @@ #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). +/* 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" @@ -54,21 +54,45 @@ #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 */ - -// 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() +#include <sys/types.h> /* for _off_t */ +#include <assert.h> +#include <stdlib.h> /* for rand, srand, _strtoxxx */ + +/* + * 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 __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 */ @@ -83,53 +107,78 @@ 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 +#endif /* #ifndef HAVE_STDINT_H */ -// I guess MSVC's <types.h> doesn't include ssize_t by default? +/* I guess MSVC's <types.h> doesn't include ssize_t by default? */ #ifdef _MSC_VER typedef intptr_t ssize_t; #endif -// ----------------------------------- THREADS +/* ----------------------------------- THREADS */ -#ifndef HAVE_PTHREAD // not true for MSVC, but may be true for MSYS +#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 -#define pthread_self GetCurrentThreadId -#define pthread_equal(pthread_t_1, pthread_t_2) ((pthread_t_1)==(pthread_t_2)) +enum { PTHREAD_ONCE_INIT = 0 }; /* important that this be 0! for SpinLock */ + +inline pthread_t pthread_self(void) { + return GetCurrentThreadId(); +} #ifdef __cplusplus -// 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) +inline bool pthread_equal(pthread_t left, pthread_t right) { + return left == right; +} + +/* 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; } -#define perftools_pthread_setspecific(key, val) \ - TlsSetValue((key), (val)) -// NOTE: this is Win2K and later. For Win98 we could use a CRITICAL_SECTION... -#define perftools_pthread_once(once, init) do { \ - if (InterlockedCompareExchange(once, 1, 0) == 0) (init)(); \ -} while (0) -#endif // __cplusplus -#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. + +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 */ +#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. +/* + * 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, @@ -197,51 +246,80 @@ class SpinLockHolder { // Acquires a spinlock for as long as the scope lasts // This keeps us from using base/spinlock.h's implementation of SpinLock. #define BASE_SPINLOCK_H_ 1 -#endif // #if 0 - -// 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); +#endif /* #if 0 */ +/* ----------------------------------- MMAP and other memory allocation */ -// ----------------------------------- MMAP and other memory allocation - -#ifndef HAVE_MMAP // not true for MSVC, but may be true for msys +#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 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 +#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 ) +#if __STDC__ +typedef _off_t off_t; +#endif -#define munmap(start, length) (VirtualFree(start, 0, MEM_RELEASE) ? 0 : -1) -#endif // HAVE_MMAP +/* 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; + } +} -// We could maybe use VirtualAlloc for sbrk as well, but no need -#define sbrk(increment) ( (void*)-1 ) // sbrk returns -1 on failure +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 (!)). -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) +/* ----------------------------------- 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" @@ -256,84 +334,132 @@ extern PERFTOOLS_DLL_DECL int safe_vsnprintf(char *str, size_t size, # define PRIxPTR "lx" #endif -// ----------------------------------- FILE IO +/* ----------------------------------- 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) #ifndef O_RDONLY #define O_RDONLY _O_RDONLY #endif -#ifdef __cplusplus -extern "C" +#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); +} #endif -PERFTOOLS_DLL_DECL void WriteToStderr(const char* buf, int len); -// ----------------------------------- SYSTEM/PROCESS -typedef int pid_t; -#define getpid _getpid -#define getppid() (0) +inline FILE *popen(const char *command, const char *type) { + return _popen(command, type); +} +inline int pclose(FILE *stream) { + return _pclose(stream); +} + +EXTERN_C PERFTOOLS_DLL_DECL void WriteToStderr(const char* buf, int len); + +/* ----------------------------------- SYSTEM/PROCESS */ -// Handle case when poll is used to simulate sleep. -#define poll(r, w, t) \ - do { \ - assert(r == 0); \ - assert(w == 0); \ - Sleep(t); \ - } while(0) +typedef int pid_t; +#if __STDC__ +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 PERFTOOLS_DLL_DECL int getpagesize(); // in port.cc +EXTERN_C int getpagesize(); /* in port.cc */ -// ----------------------------------- OTHER +/* ----------------------------------- OTHER */ -#define srandom srand -#define random rand -#define sleep(t) Sleep(t * 1000) +inline void srandom(unsigned int seed) { srand(seed); } +inline long random(void) { return rand(); } +inline unsigned int sleep(unsigned int seconds) { + Sleep(seconds * 1000); + return 0; +} struct timespec { int tv_sec; int tv_nsec; }; -#define nanosleep(tm_ptr, ignored) \ - Sleep((tm_ptr)->tv_sec * 1000 + (tm_ptr)->tv_nsec / 1000000) +inline int nanosleep(const struct timespec *req, struct timespec *rem) { + Sleep(req->tv_sec * 1000 + req->tv_nsec / 1000000); + return 0; +} #ifndef __MINGW32__ -#define strtoq _strtoi64 -#define strtouq _strtoui64 -#define strtoll _strtoi64 -#define strtoull _strtoui64 -#define atoll _atoi64 +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); +} +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-SPECIFIC */ -// tcmalloc.cc calls this so we can patch VirtualAlloc() et al. -extern PERFTOOLS_DLL_DECL void PatchWindowsFunctions(); +/* tcmalloc.cc calls this so we can patch VirtualAlloc() et al. */ +extern void PatchWindowsFunctions(); // ----------------------------------- 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. +/* + * 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 #endif /* _WIN32 */ +#undef inline +#undef EXTERN_C + #endif /* GOOGLE_BASE_WINDOWS_H_ */ |