Home | History | Annotate | Download | only in tsan
      1 /* Copyright (c) 2008-2010, 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  *     * Neither the name of Google Inc. nor the names of its
     11  * contributors may be used to endorse or promote products derived from
     12  * this software without specific prior written permission.
     13  *
     14  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     15  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     16  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     17  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     18  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     19  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     20  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     21  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     22  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     24  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     25  */
     26 
     27 // This file is part of ThreadSanitizer, a dynamic data race detector.
     28 // Author: Konstantin Serebryany.
     29 // Author: Timur Iskhodzhanov.
     30 //
     31 // See ts_util.h for mode details.
     32 
     33 #include "common_util.h"
     34 #include "thread_sanitizer.h"
     35 #include "ts_stats.h"
     36 #include "ts_lock.h"
     37 #include <stdarg.h>
     38 
     39 FLAGS *G_flags = NULL;
     40 
     41 #if defined(_MSC_VER)
     42 
     43 #pragma comment(lib, "winmm.lib")
     44 
     45 # ifdef TS_PIN
     46 #  include "pin.H"
     47 # endif
     48 namespace WINDOWS
     49 {
     50 // This is the way of including winows.h recommended by PIN docs.
     51 #include<Windows.h>
     52 }
     53 int getpid() { return WINDOWS::GetCurrentProcessId(); }
     54 #endif
     55 
     56 #if defined(TS_VALGRIND)
     57 size_t TimeInMilliSeconds() {
     58   return VG_(read_millisecond_timer)();
     59 }
     60 #else
     61 // TODO(kcc): implement this.
     62 size_t TimeInMilliSeconds() {
     63 #ifdef __GNUC__
     64   return time(0) * 1000;
     65 #else
     66   return WINDOWS::timeGetTime();
     67 #endif
     68 }
     69 #endif
     70 
     71 Stats *G_stats;
     72 
     73 #ifndef TS_LLVM
     74 bool GetNameAndOffsetOfGlobalObject(uintptr_t addr,
     75                                     string *name, uintptr_t *offset) {
     76 # ifdef TS_VALGRIND
     77     const int kBufLen = 1023;
     78     char buff[kBufLen+1];
     79     PtrdiffT off;
     80     if (VG_(get_datasym_and_offset)(addr, reinterpret_cast<Char*>(buff),
     81                                     kBufLen, &off)) {
     82       *name = buff;
     83       *offset = off;
     84       return true;
     85     }
     86     return false;
     87 # else
     88   return false;
     89 # endif  // TS_VALGRIND
     90 }
     91 #endif  // TS_LLVM
     92 
     93 
     94 #ifndef TS_VALGRIND
     95 void GetThreadStack(int tid, uintptr_t *min_addr, uintptr_t *max_addr) {
     96   *min_addr = 0xfffa;
     97   *max_addr = 0xfffb;
     98 }
     99 #endif
    100 
    101 static int n_errs_found;
    102 
    103 void SetNumberOfFoundErrors(int n_errs) {
    104   n_errs_found = n_errs;
    105 }
    106 
    107 int GetNumberOfFoundErrors() {
    108   return n_errs_found;
    109 }
    110 
    111 
    112 #if !defined(TS_VALGRIND) && !defined(TS_LLVM)
    113 FILE *G_out = stderr;
    114 #endif
    115 
    116 #ifdef TS_LLVM
    117 FILE *G_out;
    118 #endif
    119 
    120 static string RemoveUnsupportedFormat(const char *str) {
    121 #ifdef _MSC_VER
    122   // replace "%'" with "%"
    123   string res;
    124   size_t n = strlen(str);
    125   if (n == 0) {
    126     return "";
    127   }
    128   res.reserve(n);
    129   res.push_back(str[0]);
    130   for (size_t i = 1; i < n; i++) {
    131     if (str[i] == '\'' && *res.rbegin() == '%') continue;
    132     res.push_back(str[i]);
    133   }
    134   return res;
    135 #else
    136   return str;
    137 #endif
    138 }
    139 
    140 void Printf(const char *format, ...) {
    141 #ifdef TS_VALGRIND
    142   va_list args;
    143   va_start(args, format);
    144   VG_(vprintf)(format, args);
    145   va_end(args);
    146 #else
    147   va_list args;
    148   va_start(args, format);
    149   vfprintf(G_out, RemoveUnsupportedFormat(format).c_str(), args);
    150   fflush(G_out);
    151   va_end(args);
    152 #endif
    153 }
    154 
    155 // Like Print(), but prepend each line with ==XXXXX==,
    156 // where XXXXX is the pid.
    157 void Report(const char *format, ...) {
    158   int buff_size = 1024*16;
    159   char *buff = new char[buff_size];
    160   CHECK(buff);
    161   DCHECK(G_flags);
    162 
    163   va_list args;
    164 
    165   while (1) {
    166     va_start(args, format);
    167     int ret = vsnprintf(buff, buff_size,
    168                         RemoveUnsupportedFormat(format).c_str(), args);
    169     va_end(args);
    170     if (ret < buff_size) break;
    171     delete [] buff;
    172     buff_size *= 2;
    173     buff = new char[buff_size];
    174     CHECK(buff);
    175     // Printf("Resized buff: %d\n", buff_size);
    176   }
    177 
    178   char pid_buff[100];
    179   snprintf(pid_buff, sizeof(pid_buff), "==%d== ", getpid());
    180 
    181   string res;
    182 #ifndef TS_LLVM
    183   int len = strlen(buff);
    184 #else
    185   int len = __real_strlen(buff);
    186 #endif
    187   bool last_was_new_line = true;
    188   for (int i = 0; i < len; i++) {
    189     if (G_flags->show_pid && last_was_new_line)
    190       res += pid_buff;
    191     last_was_new_line = (buff[i] == '\n');
    192     res += buff[i];
    193   }
    194 
    195   delete [] buff;
    196 
    197   Printf("%s", res.c_str());
    198 }
    199 
    200 long my_strtol(const char *str, char **end, int base) {
    201 #ifdef TS_VALGRIND
    202   if (base == 16 || (base == 0 && str && str[0] == '0' && str[1] == 'x')) {
    203     return VG_(strtoll16)((Char*)str, (Char**)end);
    204   }
    205   return VG_(strtoll10)((Char*)str, (Char**)end);
    206 #else
    207   return strtoll(str, end, base);
    208 #endif
    209 }
    210 
    211 // Not thread-safe. Need to make it thread-local if we allow
    212 // malloc to be called concurrently.
    213 MallocCostCenterStack g_malloc_stack;
    214 
    215 size_t GetVmSizeInMb() {
    216 #ifdef VGO_linux
    217   const char *path ="/proc/self/statm";  // see 'man proc'
    218   uintptr_t counter = G_stats->read_proc_self_stats++;
    219   if (counter >= 1024 && ((counter & (counter - 1)) == 0))
    220     Report("INFO: reading %s for %ld'th time\n", path, counter);
    221   int  fd = OpenFileReadOnly(path, false);
    222   if (fd < 0) return 0;
    223   char buff[128];
    224   int n_read = read(fd, buff, sizeof(buff) - 1);
    225   buff[n_read] = 0;
    226   close(fd);
    227   char *end;
    228   size_t vm_size_in_pages = my_strtol(buff, &end, 10);
    229   return vm_size_in_pages >> 8;
    230 #else
    231   return 0;
    232 #endif
    233 }
    234 
    235 static string StripTemplatesFromFunctionName(const string &fname) {
    236   // Returns "" in case of error.
    237 
    238   string ret;
    239   size_t read_pointer = 0, braces_depth = 0;
    240 
    241   while (read_pointer < fname.size()) {
    242     size_t next_brace = fname.find_first_of("<>", read_pointer);
    243     if (next_brace == fname.npos) {
    244       if (braces_depth > 0) {
    245         // This can happen on Visual Studio if we reach the ~2000 char limit.
    246         CHECK(fname.size() > 256);
    247         return "";
    248       }
    249       ret += (fname.c_str() + read_pointer);
    250       break;
    251     }
    252 
    253     if (braces_depth == 0) {
    254       ret.append(fname, read_pointer, next_brace - read_pointer);
    255     }
    256 
    257     if (next_brace > 0) {
    258       // We could have found one of the following operators.
    259       const char *OP[] = {">>=", "<<=",
    260                           ">>", "<<",
    261                           ">=", "<=",
    262                           "->", "->*",
    263                           "<", ">"};
    264 
    265       bool operator_name = false;
    266       for (size_t i = 0; i < TS_ARRAY_SIZE(OP); i++) {
    267         size_t op_offset = ((string)OP[i]).find(fname[next_brace]);
    268         if (op_offset == string::npos)
    269           continue;
    270         if (next_brace >= 8 + op_offset &&  // 8 == strlen("operator");
    271             "operator" == fname.substr(next_brace - (8 + op_offset), 8) &&
    272             OP[i] == fname.substr(next_brace - op_offset, strlen(OP[i]))) {
    273           operator_name = true;
    274           ret += OP[i] + op_offset;
    275           next_brace += strlen(OP[i] + op_offset);
    276           read_pointer = next_brace;
    277           break;
    278         }
    279       }
    280 
    281       if (operator_name)
    282         continue;
    283     }
    284 
    285     if (fname[next_brace] == '<') {
    286       braces_depth++;
    287       read_pointer = next_brace + 1;
    288     } else if (fname[next_brace] == '>') {
    289       if (braces_depth == 0) {
    290         // Going to `braces_depth == -1` IS possible at least for this function on Windows:
    291         // "std::operator<<char,std::char_traits<char>,std::allocator<char> >".
    292         // Oh, well... Return an empty string and let the caller decide.
    293         return "";
    294       }
    295       braces_depth--;
    296       read_pointer = next_brace + 1;
    297     } else
    298       CHECK(0);
    299   }
    300   if (braces_depth != 0) {
    301     CHECK(fname.size() > 256);
    302     return "";
    303   }
    304   return ret;
    305 }
    306 
    307 static string StripParametersFromFunctionName(const string &demangled) {
    308   // Returns "" in case of error.
    309 
    310   string fname = demangled;
    311 
    312   // Strip stuff like "(***)" and "(anonymous namespace)" -> they are tricky.
    313   size_t found = fname.npos;
    314   while ((found = fname.find(", ")) != fname.npos)
    315     fname.erase(found+1, 1);
    316   while ((found = fname.find("(**")) != fname.npos)
    317     fname.erase(found+2, 1);
    318   while ((found = fname.find("(*)")) != fname.npos)
    319     fname.erase(found, 3);
    320   while ((found = fname.find("const()")) != fname.npos)
    321     fname.erase(found+5, 2);
    322   while ((found = fname.find("const volatile")) != fname.npos &&
    323          found > 1 && found + 14 == fname.size())
    324     fname.erase(found-1);
    325   while ((found = fname.find("(anonymous namespace)")) != fname.npos)
    326     fname.erase(found, 21);
    327 
    328   if (fname.find_first_of("(") == fname.npos)
    329     return fname;
    330   DCHECK(count(fname.begin(), fname.end(), '(') ==
    331          count(fname.begin(), fname.end(), ')'));
    332 
    333   string ret;
    334   bool returns_fun_ptr = false;
    335   size_t braces_depth = 0, read_pointer = 0;
    336 
    337   size_t first_parenthesis = fname.find("(");
    338   if (first_parenthesis != fname.npos) {
    339     DCHECK(fname.find_first_of(")") != fname.npos);
    340     DCHECK(fname.find_first_of(")") > first_parenthesis);
    341     DCHECK(fname[first_parenthesis] == '(');
    342     if (first_parenthesis + 2 < fname.size() &&
    343         fname[first_parenthesis - 1] == ' ' &&
    344         fname[first_parenthesis + 1] == '*' &&
    345         fname[first_parenthesis + 2] != ' ') {
    346       // Return value type is a function pointer
    347       read_pointer = first_parenthesis + 2;
    348       while (fname[read_pointer] == '*' || fname[read_pointer] == '&')
    349         read_pointer++;
    350       braces_depth = 1;
    351       returns_fun_ptr = true;
    352     }
    353   }
    354 
    355   while (read_pointer < fname.size()) {
    356     size_t next_brace = fname.find_first_of("()", read_pointer);
    357     if (next_brace == fname.npos) {
    358       if (braces_depth != 0) {
    359         // Overflow?
    360         return "";
    361       }
    362       size_t _const = fname.find(" const", read_pointer);
    363       if (_const == fname.npos) {
    364         ret += (fname.c_str() + read_pointer);
    365       } else {
    366         CHECK(_const + 6 == fname.size());
    367         ret.append(fname, read_pointer, _const - read_pointer);
    368       }
    369       break;
    370     }
    371 
    372     if (braces_depth == (returns_fun_ptr ? 1 : 0)) {
    373       ret.append(fname, read_pointer, next_brace - read_pointer);
    374       returns_fun_ptr = false;
    375     }
    376 
    377     if (fname[next_brace] == '(') {
    378       if (next_brace >= 8 && fname[next_brace+1] == ')' &&
    379           "operator" == fname.substr(next_brace - 8, 8)) {
    380         ret += "()";
    381         read_pointer = next_brace + 2;
    382       } else {
    383         braces_depth++;
    384         read_pointer = next_brace + 1;
    385       }
    386     } else if (fname[next_brace] == ')') {
    387       CHECK(braces_depth > 0);
    388       braces_depth--;
    389       read_pointer = next_brace + 1;
    390     } else
    391       CHECK(0);
    392   }
    393   if (braces_depth != 0)
    394     return "";
    395 
    396   // Special case: on Linux, Valgrind prepends the return type for template
    397   // functions. And on Windows we may see `scalar deleting destructor'.
    398   // And we may see "operaror new" etc.
    399   // And some STL code inserts const& between the return type and the function
    400   // name.
    401   // Oh, well...
    402   size_t space_or_tick;
    403   while (ret != "") {
    404     space_or_tick = ret.find_first_of("` ");
    405     if (space_or_tick != ret.npos && ret[space_or_tick] == ' ' &&
    406         ret.substr(0, space_or_tick).find("operator") == string::npos) {
    407       ret = ret.substr(space_or_tick + 1);
    408     } else if (space_or_tick != ret.npos && space_or_tick + 1 == ret.size()) {
    409       ret = ret.substr(0, space_or_tick);
    410     } else {
    411       break;
    412     }
    413   }
    414   return ret;
    415 }
    416 
    417 string NormalizeFunctionName(const string &demangled) {
    418   if (demangled[1] == '[' && strchr("+-=", demangled[0]) != NULL) {
    419     // Objective-C function
    420     return demangled;
    421   }
    422 
    423   if (demangled.find_first_of("<>()") == demangled.npos) {
    424     // C function or a well-formatted function name.
    425     return demangled;
    426   }
    427 
    428   if (demangled == "(below main)" || demangled == "(no symbols)")
    429     return demangled;
    430 
    431   const char* const MALFORMED = "(malformed frame)";
    432 
    433   string fname = StripTemplatesFromFunctionName(demangled);
    434   if (fname.size() == 0) {
    435     if (DEBUG_MODE)
    436       Printf("PANIC: `%s`\n", demangled.c_str());
    437     return MALFORMED;
    438   }
    439 
    440   fname = StripParametersFromFunctionName(fname);
    441   if (fname.size() == 0) {
    442     CHECK(demangled.size() >= 256);
    443     if (DEBUG_MODE)
    444       Printf("PANIC: `%s`\n", demangled.c_str());
    445     return MALFORMED;
    446   }
    447 
    448   return fname;
    449 }
    450 
    451 void OpenFileWriteStringAndClose(const string &file_name, const string &str) {
    452 #ifdef TS_VALGRIND
    453   SysRes sres = VG_(open)((const Char*)file_name.c_str(),
    454                           VKI_O_WRONLY|VKI_O_CREAT|VKI_O_TRUNC,
    455                           VKI_S_IRUSR|VKI_S_IWUSR);
    456   if (sr_isError(sres)) {
    457     Report("WARNING: can not open file %s\n", file_name.c_str());
    458     exit(1);
    459   }
    460   int fd = sr_Res(sres);
    461   write(fd, str.c_str(), str.size());
    462   close(fd);
    463 #else
    464   CHECK(0);
    465 #endif
    466 }
    467 
    468 //--------- Sockets ------------------ {{{1
    469 #if defined(TS_PIN) && defined(__GNUC__)
    470 #include <sys/types.h>
    471 #include <sys/socket.h>
    472 #include <netinet/in.h>
    473 #include <netdb.h>
    474 FILE *OpenSocketForWriting(const string &host_and_port) {
    475   size_t col = host_and_port.find(":");
    476   if (col == string::npos) return NULL;
    477   string host = host_and_port.substr(0, col);
    478   string port_str = host_and_port.substr(col + 1);
    479   int sockfd;
    480   struct sockaddr_in serv_addr;
    481   struct hostent *server;
    482   sockfd = socket(AF_INET, SOCK_STREAM, 0);
    483   if (sockfd < 0) return NULL;
    484   server = gethostbyname(host.c_str());
    485   if (server == 0) return NULL;
    486   memset(&serv_addr, 0, sizeof(serv_addr));
    487   serv_addr.sin_family = AF_INET;
    488   memcpy((char *)&serv_addr.sin_addr.s_addr,
    489          (char *)server->h_addr,
    490          server->h_length);
    491   serv_addr.sin_port = htons(atoi(port_str.c_str()));
    492   if (connect(sockfd, (struct sockaddr*)&serv_addr, sizeof(serv_addr)) < 0)
    493     return NULL;
    494   return fdopen(sockfd, "w");
    495 }
    496 #else
    497 FILE *OpenSocketForWriting(const string &host_and_port) {
    498   return NULL;  // unimplemented.
    499 }
    500 #endif
    501 //--------- TSLock ------------------ {{{1
    502 #ifdef _MSC_VER
    503 //# define TS_LOCK_PIPE
    504 # define TS_LOCK_PIN
    505 #else
    506 # define TS_LOCK_FUTEX
    507 #endif
    508 
    509 #if defined(TS_LOCK_PIPE) && defined(TS_PIN)
    510 #ifdef __GNUC__
    511 #include <unistd.h>
    512 // Lock based on pipe's send/receive. The idea (but not the code)
    513 // is shamelessly stolen from valgrind's /coregrind/m_scheduler/sema.c
    514 struct TSLock::Rep {
    515   bool held;
    516   char pipe_char;
    517   int pipe_fd[2];
    518 
    519   void Write() {
    520     char buf[2];
    521     buf[0] = pipe_char;
    522     buf[1] = 0;
    523     int res = write(pipe_fd[1], buf, 1);
    524     CHECK(res == 1);
    525   }
    526   bool Read() {
    527     char buf[2];
    528     buf[0] = 0;
    529     buf[1] = 0;
    530     int res = read(pipe_fd[0], buf, 1);
    531     if (res != 1)
    532       return false;
    533     //Printf("rep::Read: %c\n", buf[0]);
    534 
    535     pipe_char++;
    536     if (pipe_char == 'Z' + 1) pipe_char = 'A';
    537     return true;
    538   }
    539   void Open() {
    540     CHECK(0 == pipe(pipe_fd));
    541     CHECK(pipe_fd[0] != pipe_fd[1]);
    542     pipe_char = 'A';
    543   }
    544   void Close() {
    545     close(pipe_fd[0]);
    546     close(pipe_fd[1]);
    547   }
    548 };
    549 #elif defined(_MSC_VER)
    550 struct TSLock::Rep {
    551   bool held;
    552   char pipe_char;
    553   WINDOWS::HANDLE pipe_fd[2];
    554   void Write() {
    555     char buf[2];
    556     buf[0] = pipe_char;
    557     buf[1] = 0;
    558     WINDOWS::DWORD n_written = 0;
    559     int res = WINDOWS::WriteFile(pipe_fd[1], buf, 1, &n_written, NULL);
    560     CHECK(res != 0 && n_written == 1);
    561   }
    562   bool Read() {
    563     char buf[2];
    564     buf[0] = 0;
    565     buf[1] = 0;
    566     WINDOWS::DWORD n_read  = 0;
    567     int res = WINDOWS::ReadFile(pipe_fd[0], buf, 1, &n_read, NULL);
    568     if (res == 0 && n_read == 0)
    569       return false;
    570     //Printf("rep::Read: %c\n", buf[0]);
    571 
    572     pipe_char++;
    573     if (pipe_char == 'Z' + 1) pipe_char = 'A';
    574     return true;
    575   }
    576   void Open() {
    577     CHECK(WINDOWS::CreatePipe(&pipe_fd[0], &pipe_fd[1], NULL, 0));
    578     CHECK(pipe_fd[0] != pipe_fd[1]);
    579     pipe_char = 'A';
    580   }
    581   void Close() {
    582     WINDOWS::CloseHandle(pipe_fd[0]);
    583     WINDOWS::CloseHandle(pipe_fd[1]);
    584   }
    585 };
    586 #endif
    587 
    588 TSLock::TSLock() {
    589   rep_ = new Rep;
    590   rep_->held = false;
    591   rep_->Open();
    592   rep_->Write();
    593 }
    594 TSLock::~TSLock() {
    595   rep_->Close();
    596 }
    597 void TSLock::Lock() {
    598   while(rep_->Read() == false)
    599     ;
    600   rep_->held = true;
    601 }
    602 void TSLock::Unlock() {
    603   rep_->held = false;
    604   rep_->Write();
    605 }
    606 void TSLock::AssertHeld() {
    607   DCHECK(rep_->held);
    608 }
    609 #endif  // __GNUC__ & TS_LOCK_PIPE
    610 
    611 #if defined(TS_LOCK_PIN) && defined(TS_PIN)
    612 #include "pin.H"
    613 struct TSLock::Rep {
    614   PIN_LOCK lock;
    615   bool held;
    616 };
    617 
    618 TSLock::TSLock() {
    619   rep_ = new Rep();
    620   rep_->held = false;
    621   InitLock(&rep_->lock);
    622 }
    623 TSLock::~TSLock() {
    624   delete rep_;
    625 }
    626 void TSLock::Lock() {
    627   GetLock(&rep_->lock, __LINE__);
    628   rep_->held = true;
    629 }
    630 void TSLock::Unlock() {
    631   rep_->held = false;
    632   ReleaseLock(&rep_->lock);
    633 }
    634 void TSLock::AssertHeld() {
    635   DCHECK(rep_->held);
    636 }
    637 #endif  // TS_LOCK_PIN
    638 
    639 #if defined(TS_WRAP_PTHREAD_LOCK)
    640 #include "tsan_rtl_wrap.h"
    641 
    642 struct TSLock::Rep {
    643   pthread_mutex_t lock;
    644   bool held;
    645 };
    646 TSLock::TSLock() {
    647   rep_ = new Rep();
    648   rep_->held = false;
    649   __real_pthread_mutex_init(&rep_->lock, NULL);
    650 }
    651 TSLock::~TSLock() {
    652   __real_pthread_mutex_destroy(&rep_->lock);
    653   delete rep_;
    654 }
    655 void TSLock::Lock() {
    656   __real_pthread_mutex_lock(&rep_->lock);
    657   rep_->held = true;
    658 }
    659 void TSLock::Unlock() {
    660   rep_->held = false;
    661   __real_pthread_mutex_unlock(&rep_->lock);
    662 }
    663 void TSLock::AssertHeld() {
    664   DCHECK(rep_->held);
    665 }
    666 #endif  // TS_LLVM
    667 
    668 #if defined(TS_LOCK_FUTEX) && defined(__GNUC__) && \
    669  (defined (TS_PIN) || defined (TS_LLVM))
    670 #include <linux/futex.h>
    671 #include <sys/time.h>
    672 #include <syscall.h>
    673 
    674 // Simple futex-based lock.
    675 // The idea is taken from "Futexes Are Tricky" by Ulrich Drepper
    676 
    677 TSLock::TSLock() {
    678   rep_ = 0;
    679   ANNOTATE_BENIGN_RACE(&rep_, "Benign race on TSLock::rep_");
    680   ANNOTATE_RWLOCK_CREATE(this);
    681 }
    682 TSLock::~TSLock() {
    683   ANNOTATE_RWLOCK_DESTROY(this);
    684   DCHECK(rep_ == 0);
    685 }
    686 void TSLock::Lock() {
    687   int *p = (int*)&rep_;
    688   const int kSpinCount = 100;
    689   DCHECK(kSpinCount > 0);
    690   int c;
    691   for (int i = 0; i < kSpinCount; i++) {
    692     c = __sync_val_compare_and_swap(p, 0, 1);
    693     if (c == 0) break;
    694   }
    695   if (c == 0) {
    696     // The mutex was unlocked. Now it's ours. Done.
    697     ANNOTATE_RWLOCK_ACQUIRED(this, /*is_w*/true);
    698     return;
    699   }
    700   DCHECK(c == 1 || c == 2);
    701   // We are going to block on this lock. Make sure others know that.
    702   if (c != 2) {
    703     c = __sync_lock_test_and_set(p, 2);
    704   }
    705   // Block.
    706   int n_waits = 0;
    707   while (c != 0) {
    708     syscall(SYS_futex, p, FUTEX_WAIT, 2, 0, 0, 0);
    709     n_waits++;
    710     c = __sync_lock_test_and_set(p, 2);
    711   }
    712   ANNOTATE_RWLOCK_ACQUIRED(this, /*is_w*/true);
    713   G_stats->futex_wait += n_waits;
    714 }
    715 void TSLock::Unlock() {
    716   ANNOTATE_RWLOCK_RELEASED(this, /*is_w*/true);
    717   int *p = (int*)&rep_;
    718   DCHECK(*p == 1 || *p == 2);
    719   int c = __sync_sub_and_fetch(p, 1);
    720   DCHECK(c == 0 || c == 1);
    721   if (c == 1) {
    722     *p = 0;
    723     syscall(SYS_futex, p, FUTEX_WAKE, 1, 0, 0, 0);
    724   }
    725 }
    726 void TSLock::AssertHeld() {
    727   DCHECK(rep_);
    728 }
    729 #endif
    730 
    731 // Same as above to compile Go's rtl
    732 // No annotations in this version: it should be simple as possible.
    733 #if defined(TS_LOCK_FUTEX) && defined(__GNUC__) && \
    734   (defined (TS_GO))
    735 #include <linux/futex.h> // TODO(mpimenov): portability?
    736 #include <sys/time.h>
    737 #include <syscall.h>
    738 
    739 // Simple futex-based lock.
    740 // The idea is taken from "Futexes Are Tricky" by Ulrich Drepper
    741 
    742 TSLock::TSLock() {
    743   rep_ = 0;
    744 }
    745 TSLock::~TSLock() {
    746   DCHECK(rep_ == 0);
    747 }
    748 void TSLock::Lock() {
    749   int *p = (int*)&rep_;
    750   const int kSpinCount = 100;
    751   DCHECK(kSpinCount > 0);
    752   int c;
    753   for (int i = 0; i < kSpinCount; i++) {
    754     c = __sync_val_compare_and_swap(p, 0, 1);
    755     if (c == 0) break;
    756   }
    757   if (c == 0) {
    758     // The mutex was unlocked. Now it's ours. Done.
    759     return;
    760   }
    761   DCHECK(c == 1 || c == 2);
    762   // We are going to block on this lock. Make sure others know that.
    763   if (c != 2) {
    764     c = __sync_lock_test_and_set(p, 2);
    765   }
    766   // Block.
    767   int n_waits = 0;
    768   while (c != 0) {
    769     syscall(SYS_futex, p, FUTEX_WAIT, 2, 0, 0, 0);
    770     n_waits++;
    771     c = __sync_lock_test_and_set(p, 2);
    772   }
    773   G_stats->futex_wait += n_waits;
    774 }
    775 void TSLock::Unlock() {
    776   int *p = (int*)&rep_;
    777   DCHECK(*p == 1 || *p == 2);
    778   int c = __sync_sub_and_fetch(p, 1);
    779   DCHECK(c == 0 || c == 1);
    780   if (c == 1) {
    781     *p = 0;
    782     syscall(SYS_futex, p, FUTEX_WAKE, 1, 0, 0, 0);
    783   }
    784 }
    785 void TSLock::AssertHeld() {
    786   DCHECK(rep_);
    787 }
    788 #endif // (TS_LOCK_FUTEX) (__GNUC__) && (TS_GO)
    789 
    790 //--------------- Atomics ----------------- {{{1
    791 #if defined (_MSC_VER) && TS_SERIALIZED == 0
    792 uintptr_t AtomicExchange(uintptr_t *ptr, uintptr_t new_value) {
    793   return _InterlockedExchange((volatile WINDOWS::LONG*)ptr, new_value);
    794 }
    795 
    796 void ReleaseStore(uintptr_t *ptr, uintptr_t value) {
    797   *(volatile uintptr_t*)ptr = value;
    798   // TODO(kcc): anything to add here?
    799 }
    800 
    801 int32_t NoBarrier_AtomicIncrement(int32_t* ptr) {
    802   return _InterlockedIncrement((volatile WINDOWS::LONG *)ptr);
    803 }
    804 
    805 int32_t NoBarrier_AtomicDecrement(int32_t* ptr) {
    806   return _InterlockedDecrement((volatile WINDOWS::LONG *)ptr);
    807 }
    808 #endif  // _MSC_VER && TS_SERIALIZED
    809 //--------------- YIELD ----------------- {{{1
    810 #if defined (_MSC_VER)
    811 #include <intrin.h>
    812 void YIELD() {
    813   WINDOWS::Sleep(0);
    814 }
    815 void PROCESSOR_YIELD() {
    816   _mm_pause();
    817 }
    818 #elif defined(TS_VALGRIND)
    819 void YIELD() {
    820 }
    821 void PROCESSOR_YIELD() {
    822 }
    823 #elif defined(__GNUC__)
    824 void YIELD() {
    825   sched_yield();
    826 }
    827 void PROCESSOR_YIELD() {
    828   __asm__ __volatile__ ("pause");
    829 }
    830 #else
    831 #error "Unknown config"
    832 #endif
    833 
    834 // end. {{{1
    835 // vim:shiftwidth=2:softtabstop=2:expandtab:tw=80
    836