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