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