1610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov/*
2610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov  This file is part of ThreadSanitizer, a dynamic data race detector.
3610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov
4610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov  Copyright (C) 2008-2008 Google Inc
5610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov     opensource@google.com
6610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov
7610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov  This program is free software; you can redistribute it and/or
8610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov  modify it under the terms of the GNU General Public License as
9610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov  published by the Free Software Foundation; either version 2 of the
10610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov  License, or (at your option) any later version.
11610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov
12610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov  This program is distributed in the hope that it will be useful, but
13610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov  WITHOUT ANY WARRANTY; without even the implied warranty of
14610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov  General Public License for more details.
16610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov
17610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov  You should have received a copy of the GNU General Public License
18610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov  along with this program; if not, write to the Free Software
19610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
20610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov  02111-1307, USA.
21610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov
22610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov  The GNU General Public License is contained in the file COPYING.
23610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov*/
24610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov
25610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov// Author: Konstantin Serebryany <opensource@google.com>
26610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov//
27610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov// Here we define few simple classes that wrap pthread primitives.
28610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov//
29610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov// We need this to create unit tests for helgrind (or similar tool)
30610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov// that will work with different threading frameworks.
31610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov//
32610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov// If one needs to test helgrind's support for another threading library,
33610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov// he/she can create a copy of this file and replace pthread_ calls
34610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov// with appropriate calls to his/her library.
35610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov//
36610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov// Note, that some of the methods defined here are annotated with
37610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov// ANNOTATE_* macros defined in dynamic_annotations.h.
38610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov//
39610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov// DISCLAIMER: the classes defined in this header file
40610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov// are NOT intended for general use -- only for unit tests.
41610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov//
42610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov#ifndef THREAD_WRAPPERS_WIN_H
43610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov#define THREAD_WRAPPERS_WIN_H
44610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov
45610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov#define _WIN32_WINNT 0x0500 // Require Windows 2000.
46610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov#include <windows.h>
47610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov#include <mmsystem.h>
48610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov
49610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov#pragma comment(lib, "winmm.lib")
50610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov
51610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov#define NO_BARRIER
52610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov#define NO_UNNAMED_SEM
53610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov#define TLS __declspec(thread)
54610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov#define NO_SPINLOCK // TODO(timurrrr): implement SpinLock
55610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov#define usleep(x) Sleep((x)/1000)
56610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov#define sleep(x) Sleep((x)*1000)
57610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov#define NOINLINE __declspec(noinline)
58610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov#define ALIGNED(x) __declspec (align(x))
59610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov
60610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanovint GetTimeInMs() {
61610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov  return (int)timeGetTime();
62610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov}
63610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov
64610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanovtypedef unsigned char  uint8_t;
65610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanovtypedef unsigned short uint16_t;
66610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanovtypedef unsigned int   uint32_t;
67610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanovtypedef unsigned long long uint64_t;
68610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanovtypedef long long int64_t;
69610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov
70610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov// This constant is true if malloc() uses mutex on your platform as this may
71610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov// introduce a happens-before arc for a pure happens-before race detector.
72610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanovstatic const bool kMallocUsesMutex = false;
73610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov
74610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanovint AtomicIncrement(volatile int *value, int increment) {
75610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov  return InterlockedExchangeAdd(reinterpret_cast<volatile LONG*>(value),
76610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov                                increment) + increment;
77610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov}
78610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov
79610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanovclass Mutex {
80610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov  friend class CondVar;
81610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov public:
82610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov  Mutex()  { ::InitializeCriticalSection(&cs_); }
83610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov  ~Mutex() { ::DeleteCriticalSection(&cs_); }
84610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov  void Lock()          { ::EnterCriticalSection(&cs_);}
85610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov  bool TryLock()       { return ::TryEnterCriticalSection(&cs_); }
86610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov  void Unlock() {
87610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov    ANNOTATE_HAPPENS_BEFORE(this);
88610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov    /*
89610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov    // TODO(timurrrr): do we need this?
90610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov    if (signal_at_unlock_) {
91610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov      CHECK(0 == pthread_cond_signal(&cv_));
92610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov    }
93610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov    */
94610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov    ::LeaveCriticalSection(&cs_);
95610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov  }
96610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov  void ReaderLock()    { Lock(); }
97610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov  bool ReaderTryLock() { return TryLock();}
98610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov  void ReaderUnlock()  { Unlock(); }
99610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov
100610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov  void LockWhen(Condition cond)            { Lock(); WaitLoop(cond); }
101610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov  void ReaderLockWhen(Condition cond)      { Lock(); WaitLoop(cond); }
102610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov  void Await(Condition cond)               { WaitLoop(cond); }
103610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov
104610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov  bool ReaderLockWhenWithTimeout(Condition cond, int millis)
105610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov    { Lock(); return WaitLoopWithTimeout(cond, millis); }
106610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov  bool LockWhenWithTimeout(Condition cond, int millis)
107610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov    { Lock(); return WaitLoopWithTimeout(cond, millis); }
108610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov  bool AwaitWithTimeout(Condition cond, int millis)
109610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov    { return WaitLoopWithTimeout(cond, millis); }
110610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov
111610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov private:
112610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov
113610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov  void WaitLoop(Condition cond) {
114610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov    while(cond.Eval() == false) {
115610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov      Unlock();
116610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov      // TODO(timurrrr)
117610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov      Sleep(10);
118610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov      Lock();
119610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov    }
120610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov    ANNOTATE_HAPPENS_AFTER(this);
121610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov  }
122610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov
123610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov  bool WaitLoopWithTimeout(Condition cond, int millis) {
124610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov    int start_time = GetTimeInMs();
125610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov
126610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov    while (cond.Eval() == false && GetTimeInMs() - start_time < millis) {
127610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov      Unlock();
128610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov      // TODO(timurrrr)
129610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov      Sleep(10);
130610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov      Lock();
131610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov    }
132610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov
133610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov    if (cond.Eval() == 0) {
134610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov      return false;
135610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov    } else {
136610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov      ANNOTATE_HAPPENS_AFTER(this);
137610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov      return true;
138610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov    }
139610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov  }
140610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov
141610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov  CRITICAL_SECTION cs_;
142610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov};
143610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov
144610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanovclass CondVar {
145610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov public:
146610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov  CondVar()   {
147610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov    signaled_ = false;
148610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov    hSignal_  = CreateEvent(NULL, false, false, NULL);
149610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov    CHECK(hSignal_ != NULL);
150610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov  }
151610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov  ~CondVar()  {
152610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov    CloseHandle(hSignal_);
153610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov  }
154610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov  void Wait(Mutex *mu) {
155610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov    while (!signaled_) {
156610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov      mu->Unlock();
157610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov      WaitForSingleObject(hSignal_, INFINITE);
158610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov      mu->Lock();
159610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov    }
160610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov    signaled_ = false;
161610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov    ANNOTATE_HAPPENS_AFTER(this);
162610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov  }
163610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov  bool WaitWithTimeout(Mutex *mu, int millis) {
164610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov    int start_time = GetTimeInMs();
165610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov
166610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov    while (!signaled_ && GetTimeInMs() - start_time < millis) {
167610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov      int curr_time = GetTimeInMs();
168610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov      if (curr_time - start_time >= millis)
169610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov        break;
170610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov      mu->Unlock();
171610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov      WaitForSingleObject(hSignal_, start_time + millis - curr_time);
172610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov      mu->Lock();
173610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov    }
174610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov    if (signaled_) {
175610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov      ANNOTATE_HAPPENS_AFTER(this);
176610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov      signaled_ = false;
177610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov      return true;
178610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov    }
179610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov    return false;
180610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov  }
181610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov  void Signal() {
182610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov    signaled_ = true;
183610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov    ANNOTATE_HAPPENS_BEFORE(this);
184610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov    SetEvent(hSignal_);
185610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov  }
186610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov// TODO(timurrrr): this isn't used anywhere - do we need these?
187610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov//  void SignalAll();
188610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov private:
189610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov  HANDLE hSignal_;
190610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov  bool signaled_;
191610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov};
192610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov
193610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanovclass MyThread {
194610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov public:
195610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov  typedef void *(*worker_t)(void*);
196610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov
197610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov  MyThread(worker_t worker, void *arg = NULL, const char *name = NULL)
198610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov      :w_(worker), arg_(arg), name_(name), t_(NULL) {}
199610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov  MyThread(void (*worker)(void), void *arg = NULL, const char *name = NULL)
200610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov      :w_(reinterpret_cast<worker_t>(worker)), arg_(arg), name_(name), t_(NULL) {}
201610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov  MyThread(void (*worker)(void *), void *arg = NULL, const char *name = NULL)
202610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov      :w_(reinterpret_cast<worker_t>(worker)), arg_(arg), name_(name), t_(NULL) {}
203610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov
204610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov  ~MyThread(){
205610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov    CloseHandle(t_);
206610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov    t_ = NULL;
207610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov  }
208610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov  void Start() {
209610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov    DWORD thr_id;
210610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov    t_ = ::CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)ThreadBody, this, 0, &thr_id);
211610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov    CHECK(t_ > 0);
212610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov  }
213610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov  void Join() {
214610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov    CHECK(t_ > 0);
215610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov    CHECK(WAIT_OBJECT_0 == ::WaitForSingleObject(t_, INFINITE));
216610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov  }
217610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov  HANDLE tid() const { return t_; }
218610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov private:
219610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov  static DWORD WINAPI ThreadBody(MyThread *my_thread) {
220610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov    if (my_thread->name_) {
221610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov      ANNOTATE_THREAD_NAME(my_thread->name_);
222610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov    }
223610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov    my_thread->w_(my_thread->arg_);
224610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov    return 0;
225610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov  }
226610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov  HANDLE t_;
227610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov  DWORD ret_;
228610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov  worker_t  w_;
229610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov  void     *arg_;
230610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov  const char *name_;
231610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov};
232610969f87667a485b9207086b3ff475bab909f95Evgeniy Stepanov#endif  // THREAD_WRAPPERS_WIN_H
233