blob: f2b273a05aa5fa3b689d84ea91425f99309e5a61 [file] [log] [blame]
Alexey Samsonov3b2f9f42012-06-04 13:55:19 +00001//===-- tsan_rtl_thread.cc ------------------------------------------------===//
Kostya Serebryany4ad375f2012-05-10 13:48:04 +00002//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10// This file is a part of ThreadSanitizer (TSan), a race detector.
11//
12//===----------------------------------------------------------------------===//
13
Alexey Samsonov8bd90982012-06-07 09:50:16 +000014#include "sanitizer_common/sanitizer_placement_new.h"
Kostya Serebryany4ad375f2012-05-10 13:48:04 +000015#include "tsan_rtl.h"
16#include "tsan_mman.h"
Kostya Serebryany4ad375f2012-05-10 13:48:04 +000017#include "tsan_platform.h"
18#include "tsan_report.h"
19#include "tsan_sync.h"
20
21namespace __tsan {
22
Dmitry Vyukovdc36d692012-07-16 16:03:16 +000023#ifndef TSAN_GO
Dmitry Vyukovf6985e32012-05-22 14:34:43 +000024const int kThreadQuarantineSize = 16;
Dmitry Vyukovdc36d692012-07-16 16:03:16 +000025#else
26const int kThreadQuarantineSize = 64;
27#endif
Kostya Serebryany4ad375f2012-05-10 13:48:04 +000028
29static void MaybeReportThreadLeak(ThreadContext *tctx) {
30 if (tctx->detached)
31 return;
32 if (tctx->status != ThreadStatusCreated
33 && tctx->status != ThreadStatusRunning
34 && tctx->status != ThreadStatusFinished)
35 return;
36 ScopedReport rep(ReportTypeThreadLeak);
37 rep.AddThread(tctx);
Dmitry Vyukov90c9cbf2012-10-05 15:51:32 +000038 OutputReport(CTX(), rep);
Kostya Serebryany4ad375f2012-05-10 13:48:04 +000039}
40
41void ThreadFinalize(ThreadState *thr) {
42 CHECK_GT(thr->in_rtl, 0);
43 if (!flags()->report_thread_leaks)
44 return;
45 Context *ctx = CTX();
46 Lock l(&ctx->thread_mtx);
Kostya Serebryany07c48052012-05-11 14:42:24 +000047 for (unsigned i = 0; i < kMaxTid; i++) {
Kostya Serebryany4ad375f2012-05-10 13:48:04 +000048 ThreadContext *tctx = ctx->threads[i];
49 if (tctx == 0)
50 continue;
51 MaybeReportThreadLeak(tctx);
Kostya Serebryany4ad375f2012-05-10 13:48:04 +000052 }
53}
54
Dmitry Vyukov67dc5702012-11-07 16:41:57 +000055int ThreadCount(ThreadState *thr) {
56 CHECK_GT(thr->in_rtl, 0);
57 Context *ctx = CTX();
58 Lock l(&ctx->thread_mtx);
59 int cnt = 0;
60 for (unsigned i = 0; i < kMaxTid; i++) {
61 ThreadContext *tctx = ctx->threads[i];
62 if (tctx == 0)
63 continue;
64 if (tctx->status != ThreadStatusCreated
65 && tctx->status != ThreadStatusRunning)
66 continue;
67 cnt++;
68 }
69 return cnt;
70}
71
Kostya Serebryany4ad375f2012-05-10 13:48:04 +000072static void ThreadDead(ThreadState *thr, ThreadContext *tctx) {
73 Context *ctx = CTX();
74 CHECK_GT(thr->in_rtl, 0);
75 CHECK(tctx->status == ThreadStatusRunning
76 || tctx->status == ThreadStatusFinished);
Alexey Samsonov51ae9832012-06-06 13:11:29 +000077 DPrintf("#%d: ThreadDead uid=%zu\n", thr->tid, tctx->user_id);
Kostya Serebryany4ad375f2012-05-10 13:48:04 +000078 tctx->status = ThreadStatusDead;
79 tctx->user_id = 0;
80 tctx->sync.Reset();
81
82 // Put to dead list.
83 tctx->dead_next = 0;
84 if (ctx->dead_list_size == 0)
85 ctx->dead_list_head = tctx;
86 else
87 ctx->dead_list_tail->dead_next = tctx;
88 ctx->dead_list_tail = tctx;
89 ctx->dead_list_size++;
90}
91
92int ThreadCreate(ThreadState *thr, uptr pc, uptr uid, bool detached) {
93 CHECK_GT(thr->in_rtl, 0);
94 Context *ctx = CTX();
95 Lock l(&ctx->thread_mtx);
96 StatInc(thr, StatThreadCreate);
97 int tid = -1;
98 ThreadContext *tctx = 0;
99 if (ctx->dead_list_size > kThreadQuarantineSize
100 || ctx->thread_seq >= kMaxTid) {
101 if (ctx->dead_list_size == 0) {
Alexey Samsonovad9d65f2012-11-02 12:17:51 +0000102 Printf("ThreadSanitizer: %d thread limit exceeded. Dying.\n",
Alexey Samsonovac4c2902012-06-06 10:13:27 +0000103 kMaxTid);
Kostya Serebryany4ad375f2012-05-10 13:48:04 +0000104 Die();
105 }
106 StatInc(thr, StatThreadReuse);
107 tctx = ctx->dead_list_head;
108 ctx->dead_list_head = tctx->dead_next;
109 ctx->dead_list_size--;
110 if (ctx->dead_list_size == 0) {
111 CHECK_EQ(tctx->dead_next, 0);
112 ctx->dead_list_head = 0;
113 }
114 CHECK_EQ(tctx->status, ThreadStatusDead);
115 tctx->status = ThreadStatusInvalid;
116 tctx->reuse_count++;
Dmitry Vyukov302cebb2012-05-22 18:07:45 +0000117 tctx->sync.Reset();
Kostya Serebryany4ad375f2012-05-10 13:48:04 +0000118 tid = tctx->tid;
Dmitry Vyukovf6985e32012-05-22 14:34:43 +0000119 DestroyAndFree(tctx->dead_info);
Kostya Serebryany4ad375f2012-05-10 13:48:04 +0000120 } else {
121 StatInc(thr, StatThreadMaxTid);
122 tid = ctx->thread_seq++;
123 void *mem = internal_alloc(MBlockThreadContex, sizeof(ThreadContext));
124 tctx = new(mem) ThreadContext(tid);
125 ctx->threads[tid] = tctx;
126 }
127 CHECK_NE(tctx, 0);
128 CHECK_GE(tid, 0);
129 CHECK_LT(tid, kMaxTid);
Alexey Samsonov51ae9832012-06-06 13:11:29 +0000130 DPrintf("#%d: ThreadCreate tid=%d uid=%zu\n", thr->tid, tid, uid);
Kostya Serebryany4ad375f2012-05-10 13:48:04 +0000131 CHECK_EQ(tctx->status, ThreadStatusInvalid);
132 ctx->alive_threads++;
133 if (ctx->max_alive_threads < ctx->alive_threads) {
134 ctx->max_alive_threads++;
135 CHECK_EQ(ctx->max_alive_threads, ctx->alive_threads);
136 StatInc(thr, StatThreadMaxAlive);
137 }
138 tctx->status = ThreadStatusCreated;
139 tctx->thr = 0;
140 tctx->user_id = uid;
141 tctx->unique_id = ctx->unique_thread_seq++;
142 tctx->detached = detached;
143 if (tid) {
144 thr->fast_state.IncrementEpoch();
145 // Can't increment epoch w/o writing to the trace as well.
146 TraceAddEvent(thr, thr->fast_state.epoch(), EventTypeMop, 0);
147 thr->clock.set(thr->tid, thr->fast_state.epoch());
148 thr->fast_synch_epoch = thr->fast_state.epoch();
149 thr->clock.release(&tctx->sync);
150 StatInc(thr, StatSyncRelease);
151
152 tctx->creation_stack.ObtainCurrent(thr, pc);
153 }
154 return tid;
155}
156
Dmitry Vyukov56faa552012-10-02 12:58:14 +0000157void ThreadStart(ThreadState *thr, int tid, uptr os_id) {
Kostya Serebryany4ad375f2012-05-10 13:48:04 +0000158 CHECK_GT(thr->in_rtl, 0);
159 uptr stk_addr = 0;
160 uptr stk_size = 0;
161 uptr tls_addr = 0;
162 uptr tls_size = 0;
Dmitry Vyukov7339eb12012-05-25 11:15:04 +0000163 GetThreadStackAndTls(tid == 0, &stk_addr, &stk_size, &tls_addr, &tls_size);
Kostya Serebryany4ad375f2012-05-10 13:48:04 +0000164
Dmitry Vyukov2d4e3c12012-05-28 07:44:34 +0000165 if (tid) {
Dmitry Vyukov03d32ec2012-07-05 16:18:28 +0000166 if (stk_addr && stk_size) {
167 MemoryResetRange(thr, /*pc=*/ 1, stk_addr, stk_size);
168 }
Kostya Serebryany4ad375f2012-05-10 13:48:04 +0000169
Dmitry Vyukov03d32ec2012-07-05 16:18:28 +0000170 if (tls_addr && tls_size) {
171 // Check that the thr object is in tls;
172 const uptr thr_beg = (uptr)thr;
173 const uptr thr_end = (uptr)thr + sizeof(*thr);
174 CHECK_GE(thr_beg, tls_addr);
175 CHECK_LE(thr_beg, tls_addr + tls_size);
176 CHECK_GE(thr_end, tls_addr);
177 CHECK_LE(thr_end, tls_addr + tls_size);
178 // Since the thr object is huge, skip it.
179 MemoryResetRange(thr, /*pc=*/ 2, tls_addr, thr_beg - tls_addr);
180 MemoryResetRange(thr, /*pc=*/ 2, thr_end, tls_addr + tls_size - thr_end);
181 }
Dmitry Vyukov2d4e3c12012-05-28 07:44:34 +0000182 }
Kostya Serebryany4ad375f2012-05-10 13:48:04 +0000183
184 Lock l(&CTX()->thread_mtx);
185 ThreadContext *tctx = CTX()->threads[tid];
186 CHECK_NE(tctx, 0);
187 CHECK_EQ(tctx->status, ThreadStatusCreated);
188 tctx->status = ThreadStatusRunning;
Dmitry Vyukov27d5b372012-10-02 11:52:05 +0000189 tctx->os_id = os_id;
Kostya Serebryany4ad375f2012-05-10 13:48:04 +0000190 tctx->epoch0 = tctx->epoch1 + 1;
191 tctx->epoch1 = (u64)-1;
Dmitry Vyukov191f2f72012-08-30 13:02:30 +0000192 new(thr) ThreadState(CTX(), tid, tctx->unique_id,
193 tctx->epoch0, stk_addr, stk_size,
194 tls_addr, tls_size);
Dmitry Vyukov5bfac972012-07-16 16:44:47 +0000195#ifdef TSAN_GO
196 // Setup dynamic shadow stack.
197 const int kInitStackSize = 8;
198 thr->shadow_stack = (uptr*)internal_alloc(MBlockShadowStack,
199 kInitStackSize * sizeof(uptr));
200 thr->shadow_stack_pos = thr->shadow_stack;
201 thr->shadow_stack_end = thr->shadow_stack + kInitStackSize;
202#endif
Kostya Serebryany4ad375f2012-05-10 13:48:04 +0000203 tctx->thr = thr;
204 thr->fast_synch_epoch = tctx->epoch0;
205 thr->clock.set(tid, tctx->epoch0);
206 thr->clock.acquire(&tctx->sync);
207 StatInc(thr, StatSyncAcquire);
Alexey Samsonov51ae9832012-06-06 13:11:29 +0000208 DPrintf("#%d: ThreadStart epoch=%zu stk_addr=%zx stk_size=%zx "
209 "tls_addr=%zx tls_size=%zx\n",
210 tid, (uptr)tctx->epoch0, stk_addr, stk_size, tls_addr, tls_size);
Dmitry Vyukovfa985a02012-06-28 18:07:46 +0000211 thr->is_alive = true;
Kostya Serebryany4ad375f2012-05-10 13:48:04 +0000212}
213
214void ThreadFinish(ThreadState *thr) {
215 CHECK_GT(thr->in_rtl, 0);
216 StatInc(thr, StatThreadFinish);
217 // FIXME: Treat it as write.
218 if (thr->stk_addr && thr->stk_size)
219 MemoryResetRange(thr, /*pc=*/ 3, thr->stk_addr, thr->stk_size);
220 if (thr->tls_addr && thr->tls_size) {
221 const uptr thr_beg = (uptr)thr;
222 const uptr thr_end = (uptr)thr + sizeof(*thr);
223 // Since the thr object is huge, skip it.
224 MemoryResetRange(thr, /*pc=*/ 4, thr->tls_addr, thr_beg - thr->tls_addr);
225 MemoryResetRange(thr, /*pc=*/ 5,
226 thr_end, thr->tls_addr + thr->tls_size - thr_end);
227 }
Dmitry Vyukovfa985a02012-06-28 18:07:46 +0000228 thr->is_alive = false;
Kostya Serebryany4ad375f2012-05-10 13:48:04 +0000229 Context *ctx = CTX();
230 Lock l(&ctx->thread_mtx);
231 ThreadContext *tctx = ctx->threads[thr->tid];
232 CHECK_NE(tctx, 0);
233 CHECK_EQ(tctx->status, ThreadStatusRunning);
234 CHECK_GT(ctx->alive_threads, 0);
235 ctx->alive_threads--;
236 if (tctx->detached) {
237 ThreadDead(thr, tctx);
238 } else {
239 thr->fast_state.IncrementEpoch();
240 // Can't increment epoch w/o writing to the trace as well.
241 TraceAddEvent(thr, thr->fast_state.epoch(), EventTypeMop, 0);
242 thr->clock.set(thr->tid, thr->fast_state.epoch());
243 thr->fast_synch_epoch = thr->fast_state.epoch();
244 thr->clock.release(&tctx->sync);
245 StatInc(thr, StatSyncRelease);
246 tctx->status = ThreadStatusFinished;
247 }
248
249 // Save from info about the thread.
Dmitry Vyukovf6985e32012-05-22 14:34:43 +0000250 tctx->dead_info = new(internal_alloc(MBlockDeadInfo, sizeof(ThreadDeadInfo)))
251 ThreadDeadInfo();
Dmitry Vyukov090f3452012-06-27 21:00:23 +0000252 internal_memcpy(&tctx->dead_info->trace.events[0],
Kostya Serebryany4ad375f2012-05-10 13:48:04 +0000253 &thr->trace.events[0], sizeof(thr->trace.events));
254 for (int i = 0; i < kTraceParts; i++) {
Dmitry Vyukovf6985e32012-05-22 14:34:43 +0000255 tctx->dead_info->trace.headers[i].stack0.CopyFrom(
Kostya Serebryany4ad375f2012-05-10 13:48:04 +0000256 thr->trace.headers[i].stack0);
257 }
Dmitry Vyukov302cebb2012-05-22 18:07:45 +0000258 tctx->epoch1 = thr->fast_state.epoch();
Kostya Serebryany4ad375f2012-05-10 13:48:04 +0000259
Dmitry Vyukov9f143c52012-08-16 19:36:45 +0000260#ifndef TSAN_GO
Dmitry Vyukov954fc8c2012-08-15 15:35:15 +0000261 AlloctorThreadFinish(thr);
Dmitry Vyukov9f143c52012-08-16 19:36:45 +0000262#endif
Kostya Serebryany4ad375f2012-05-10 13:48:04 +0000263 thr->~ThreadState();
264 StatAggregate(ctx->stat, thr->stat);
Kostya Serebryany4ad375f2012-05-10 13:48:04 +0000265 tctx->thr = 0;
266}
267
268int ThreadTid(ThreadState *thr, uptr pc, uptr uid) {
269 CHECK_GT(thr->in_rtl, 0);
Dmitry Vyukov880bb662012-05-28 17:32:50 +0000270 Context *ctx = CTX();
271 Lock l(&ctx->thread_mtx);
272 int res = -1;
Kostya Serebryany07c48052012-05-11 14:42:24 +0000273 for (unsigned tid = 0; tid < kMaxTid; tid++) {
Dmitry Vyukov880bb662012-05-28 17:32:50 +0000274 ThreadContext *tctx = ctx->threads[tid];
275 if (tctx != 0 && tctx->user_id == uid
276 && tctx->status != ThreadStatusInvalid) {
277 tctx->user_id = 0;
278 res = tid;
279 break;
280 }
Kostya Serebryany4ad375f2012-05-10 13:48:04 +0000281 }
Alexey Samsonov51ae9832012-06-06 13:11:29 +0000282 DPrintf("#%d: ThreadTid uid=%zu tid=%d\n", thr->tid, uid, res);
Dmitry Vyukov880bb662012-05-28 17:32:50 +0000283 return res;
Kostya Serebryany4ad375f2012-05-10 13:48:04 +0000284}
285
286void ThreadJoin(ThreadState *thr, uptr pc, int tid) {
287 CHECK_GT(thr->in_rtl, 0);
288 CHECK_GT(tid, 0);
289 CHECK_LT(tid, kMaxTid);
290 DPrintf("#%d: ThreadJoin tid=%d\n", thr->tid, tid);
291 Context *ctx = CTX();
292 Lock l(&ctx->thread_mtx);
293 ThreadContext *tctx = ctx->threads[tid];
294 if (tctx->status == ThreadStatusInvalid) {
Alexey Samsonovad9d65f2012-11-02 12:17:51 +0000295 Printf("ThreadSanitizer: join of non-existent thread\n");
Kostya Serebryany4ad375f2012-05-10 13:48:04 +0000296 return;
297 }
298 CHECK_EQ(tctx->detached, false);
299 CHECK_EQ(tctx->status, ThreadStatusFinished);
300 thr->clock.acquire(&tctx->sync);
301 StatInc(thr, StatSyncAcquire);
302 ThreadDead(thr, tctx);
303}
304
305void ThreadDetach(ThreadState *thr, uptr pc, int tid) {
306 CHECK_GT(thr->in_rtl, 0);
307 CHECK_GT(tid, 0);
308 CHECK_LT(tid, kMaxTid);
309 Context *ctx = CTX();
310 Lock l(&ctx->thread_mtx);
311 ThreadContext *tctx = ctx->threads[tid];
312 if (tctx->status == ThreadStatusInvalid) {
Alexey Samsonovad9d65f2012-11-02 12:17:51 +0000313 Printf("ThreadSanitizer: detach of non-existent thread\n");
Kostya Serebryany4ad375f2012-05-10 13:48:04 +0000314 return;
315 }
316 if (tctx->status == ThreadStatusFinished) {
317 ThreadDead(thr, tctx);
318 } else {
319 tctx->detached = true;
320 }
321}
322
323void MemoryAccessRange(ThreadState *thr, uptr pc, uptr addr,
324 uptr size, bool is_write) {
325 if (size == 0)
326 return;
327
328 u64 *shadow_mem = (u64*)MemToShadow(addr);
329 DPrintf2("#%d: MemoryAccessRange: @%p %p size=%d is_write=%d\n",
330 thr->tid, (void*)pc, (void*)addr,
331 (int)size, is_write);
332
333#if TSAN_DEBUG
334 if (!IsAppMem(addr)) {
Alexey Samsonovad9d65f2012-11-02 12:17:51 +0000335 Printf("Access to non app mem %zx\n", addr);
Kostya Serebryany4ad375f2012-05-10 13:48:04 +0000336 DCHECK(IsAppMem(addr));
337 }
338 if (!IsAppMem(addr + size - 1)) {
Alexey Samsonovad9d65f2012-11-02 12:17:51 +0000339 Printf("Access to non app mem %zx\n", addr + size - 1);
Kostya Serebryany4ad375f2012-05-10 13:48:04 +0000340 DCHECK(IsAppMem(addr + size - 1));
341 }
342 if (!IsShadowMem((uptr)shadow_mem)) {
Alexey Samsonovad9d65f2012-11-02 12:17:51 +0000343 Printf("Bad shadow addr %p (%zx)\n", shadow_mem, addr);
Kostya Serebryany4ad375f2012-05-10 13:48:04 +0000344 DCHECK(IsShadowMem((uptr)shadow_mem));
345 }
346 if (!IsShadowMem((uptr)(shadow_mem + size * kShadowCnt / 8 - 1))) {
Alexey Samsonovad9d65f2012-11-02 12:17:51 +0000347 Printf("Bad shadow addr %p (%zx)\n",
Alexey Samsonov51ae9832012-06-06 13:11:29 +0000348 shadow_mem + size * kShadowCnt / 8 - 1, addr + size - 1);
Kostya Serebryany4ad375f2012-05-10 13:48:04 +0000349 DCHECK(IsShadowMem((uptr)(shadow_mem + size * kShadowCnt / 8 - 1)));
350 }
351#endif
352
353 StatInc(thr, StatMopRange);
354
355 FastState fast_state = thr->fast_state;
356 if (fast_state.GetIgnoreBit())
357 return;
358
359 fast_state.IncrementEpoch();
360 thr->fast_state = fast_state;
361 TraceAddEvent(thr, fast_state.epoch(), EventTypeMop, pc);
362
363 bool unaligned = (addr % kShadowCell) != 0;
364
365 // Handle unaligned beginning, if any.
366 for (; addr % kShadowCell && size; addr++, size--) {
367 int const kAccessSizeLog = 0;
368 Shadow cur(fast_state);
369 cur.SetWrite(is_write);
370 cur.SetAddr0AndSizeLog(addr & (kShadowCell - 1), kAccessSizeLog);
371 MemoryAccessImpl(thr, addr, kAccessSizeLog, is_write, fast_state,
372 shadow_mem, cur);
373 }
374 if (unaligned)
375 shadow_mem += kShadowCnt;
376 // Handle middle part, if any.
377 for (; size >= kShadowCell; addr += kShadowCell, size -= kShadowCell) {
378 int const kAccessSizeLog = 3;
379 Shadow cur(fast_state);
380 cur.SetWrite(is_write);
381 cur.SetAddr0AndSizeLog(0, kAccessSizeLog);
382 MemoryAccessImpl(thr, addr, kAccessSizeLog, is_write, fast_state,
383 shadow_mem, cur);
384 shadow_mem += kShadowCnt;
385 }
386 // Handle ending, if any.
387 for (; size; addr++, size--) {
388 int const kAccessSizeLog = 0;
389 Shadow cur(fast_state);
390 cur.SetWrite(is_write);
391 cur.SetAddr0AndSizeLog(addr & (kShadowCell - 1), kAccessSizeLog);
392 MemoryAccessImpl(thr, addr, kAccessSizeLog, is_write, fast_state,
393 shadow_mem, cur);
394 }
395}
396
397void MemoryRead1Byte(ThreadState *thr, uptr pc, uptr addr) {
398 MemoryAccess(thr, pc, addr, 0, 0);
399}
400
401void MemoryWrite1Byte(ThreadState *thr, uptr pc, uptr addr) {
402 MemoryAccess(thr, pc, addr, 0, 1);
403}
404
405void MemoryRead8Byte(ThreadState *thr, uptr pc, uptr addr) {
406 MemoryAccess(thr, pc, addr, 3, 0);
407}
408
409void MemoryWrite8Byte(ThreadState *thr, uptr pc, uptr addr) {
410 MemoryAccess(thr, pc, addr, 3, 1);
411}
412} // namespace __tsan