1/* Copyright (c) 2008-2009, 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: Kostya Serebryany 32 */ 33 34#ifdef __cplusplus 35# error "This file should be built as pure C to avoid name mangling" 36#endif 37 38#include "config.h" 39#include <stdlib.h> 40#include <string.h> 41 42#include "base/dynamic_annotations.h" 43 44#ifdef __GNUC__ 45/* valgrind.h uses gcc extensions so it won't build with other compilers */ 46# ifdef HAVE_VALGRIND_H /* prefer the user's copy if they have it */ 47# include <valgrind.h> 48# else /* otherwise just use the copy that we have */ 49# include "third_party/valgrind.h" 50# endif 51#endif 52 53/* Compiler-based ThreadSanitizer defines 54 DYNAMIC_ANNOTATIONS_EXTERNAL_IMPL = 1 55 and provides its own definitions of the functions. */ 56 57#ifndef DYNAMIC_ANNOTATIONS_EXTERNAL_IMPL 58# define DYNAMIC_ANNOTATIONS_EXTERNAL_IMPL 0 59#endif 60 61/* Each function is empty and called (via a macro) only in debug mode. 62 The arguments are captured by dynamic tools at runtime. */ 63 64#if DYNAMIC_ANNOTATIONS_ENABLED == 1 \ 65 && DYNAMIC_ANNOTATIONS_EXTERNAL_IMPL == 0 66 67void AnnotateRWLockCreate(const char *file, int line, 68 const volatile void *lock){} 69void AnnotateRWLockDestroy(const char *file, int line, 70 const volatile void *lock){} 71void AnnotateRWLockAcquired(const char *file, int line, 72 const volatile void *lock, long is_w){} 73void AnnotateRWLockReleased(const char *file, int line, 74 const volatile void *lock, long is_w){} 75void AnnotateBarrierInit(const char *file, int line, 76 const volatile void *barrier, long count, 77 long reinitialization_allowed) {} 78void AnnotateBarrierWaitBefore(const char *file, int line, 79 const volatile void *barrier) {} 80void AnnotateBarrierWaitAfter(const char *file, int line, 81 const volatile void *barrier) {} 82void AnnotateBarrierDestroy(const char *file, int line, 83 const volatile void *barrier) {} 84 85void AnnotateCondVarWait(const char *file, int line, 86 const volatile void *cv, 87 const volatile void *lock){} 88void AnnotateCondVarSignal(const char *file, int line, 89 const volatile void *cv){} 90void AnnotateCondVarSignalAll(const char *file, int line, 91 const volatile void *cv){} 92void AnnotatePublishMemoryRange(const char *file, int line, 93 const volatile void *address, 94 long size){} 95void AnnotateUnpublishMemoryRange(const char *file, int line, 96 const volatile void *address, 97 long size){} 98void AnnotatePCQCreate(const char *file, int line, 99 const volatile void *pcq){} 100void AnnotatePCQDestroy(const char *file, int line, 101 const volatile void *pcq){} 102void AnnotatePCQPut(const char *file, int line, 103 const volatile void *pcq){} 104void AnnotatePCQGet(const char *file, int line, 105 const volatile void *pcq){} 106void AnnotateNewMemory(const char *file, int line, 107 const volatile void *mem, 108 long size){} 109void AnnotateExpectRace(const char *file, int line, 110 const volatile void *mem, 111 const char *description){} 112void AnnotateBenignRace(const char *file, int line, 113 const volatile void *mem, 114 const char *description){} 115void AnnotateBenignRaceSized(const char *file, int line, 116 const volatile void *mem, 117 long size, 118 const char *description) {} 119void AnnotateMutexIsUsedAsCondVar(const char *file, int line, 120 const volatile void *mu){} 121void AnnotateTraceMemory(const char *file, int line, 122 const volatile void *arg){} 123void AnnotateThreadName(const char *file, int line, 124 const char *name){} 125void AnnotateIgnoreReadsBegin(const char *file, int line){} 126void AnnotateIgnoreReadsEnd(const char *file, int line){} 127void AnnotateIgnoreWritesBegin(const char *file, int line){} 128void AnnotateIgnoreWritesEnd(const char *file, int line){} 129void AnnotateEnableRaceDetection(const char *file, int line, int enable){} 130void AnnotateNoOp(const char *file, int line, 131 const volatile void *arg){} 132void AnnotateFlushState(const char *file, int line){} 133 134#endif /* DYNAMIC_ANNOTATIONS_ENABLED == 1 135 && DYNAMIC_ANNOTATIONS_EXTERNAL_IMPL == 0 */ 136 137#if DYNAMIC_ANNOTATIONS_EXTERNAL_IMPL == 0 138 139static int GetRunningOnValgrind(void) { 140#ifdef RUNNING_ON_VALGRIND 141 if (RUNNING_ON_VALGRIND) return 1; 142#endif 143#ifdef _MSC_VER 144 /* Visual Studio can complain about getenv, so use a windows equivalent. */ 145 char value[100] = "1"; /* something that is not "0" */ 146 int res = GetEnvironmentVariableA("RUNNING_ON_VALGRIND", 147 value, sizeof(value)); 148 /* value will remain "1" if the called failed for some reason. */ 149 return (res > 0 && strcmp(value, "0") != 0); 150#else 151 /* TODO(csilvers): use GetenvBeforeMain() instead? Will need to 152 * change it to be extern "C". 153 */ 154 char *running_on_valgrind_str = getenv("RUNNING_ON_VALGRIND"); 155 if (running_on_valgrind_str) { 156 return strcmp(running_on_valgrind_str, "0") != 0; 157 } 158 return 0; 159#endif 160} 161 162/* See the comments in dynamic_annotations.h */ 163int RunningOnValgrind(void) { 164 static volatile int running_on_valgrind = -1; 165 int local_running_on_valgrind = running_on_valgrind; 166 /* C doesn't have thread-safe initialization of statics, and we 167 don't want to depend on pthread_once here, so hack it. */ 168 ANNOTATE_BENIGN_RACE(&running_on_valgrind, "safe hack"); 169 if (local_running_on_valgrind == -1) 170 running_on_valgrind = local_running_on_valgrind = GetRunningOnValgrind(); 171 return local_running_on_valgrind; 172} 173 174#endif /* DYNAMIC_ANNOTATIONS_EXTERNAL_IMPL == 0 */ 175 176/* See the comments in dynamic_annotations.h */ 177double ValgrindSlowdown(void) { 178 /* Same initialization hack as in RunningOnValgrind(). */ 179 static volatile double slowdown = 0.0; 180 double local_slowdown = slowdown; 181 ANNOTATE_BENIGN_RACE(&slowdown, "safe hack"); 182 if (RunningOnValgrind() == 0) { 183 return 1.0; 184 } 185 if (local_slowdown == 0.0) { 186 char *env = getenv("VALGRIND_SLOWDOWN"); 187 slowdown = local_slowdown = env ? atof(env) : 50.0; 188 } 189 return local_slowdown; 190} 191