This is a pure refactoring change. It paves the way for OS-specific
implementations, such as Fuchsia's, that can do most of the
per-thread bookkeeping work in the creator thread before the new
thread actually starts. This model is simpler and cleaner, avoiding
some race issues that the interceptor code for thread creation has
to do for the existing OS-specific implementations.
Details
Diff Detail
- Repository
- rL LLVM
Event Timeline
lib/sanitizer_common/sanitizer_thread_registry.cc | ||
---|---|---|
258 | aborted = (ThreadStatusCreated == tctx->status) |
lib/sanitizer_common/sanitizer_thread_registry.cc | ||
---|---|---|
269–275 | can you remove dead and just have if (tctx->detached) { tctx->detached = false; tctx->SetDead(); QuarantinePush(tctx); } |
lib/sanitizer_common/sanitizer_thread_registry.cc | ||
---|---|---|
269–275 | I'm not sure I understand what you're suggesting. The ->detached value has no effect on SetDead that I can see. The call to SetDead must come after the call to SetFinished. For the ThreaadStatusCreated (Fuchsia) case, ->detached must be false when One option is: if (tctx->status == ThreadStatusRunning) { CHECK_GT(running_threads_, 0); running_threads_--; tctx->SetFinished(); } else { // The thread never really existed. CHECK_EQ(tctx->status, ThreadStatusCreated); tctx->detached = false; tctx->SetFinished(); tctx->detached = true; } if (tctx->detached) { tctx->SetDead(); QuarantinePush(tctx); } where SetFinished is duplicated and ->detached is re-set purely for the Another option is: if (tctx->status == ThreadStatusRunning) { CHECK_GT(running_threads_, 0); running_threads_--; tctx->SetFinished(); if (tctx->detached) { tctx->SetDead(); QuarantinePush(tctx); } } else { // The thread never really existed. CHECK_EQ(tctx->status, ThreadStatusCreated); tctx->detached = false; tctx->SetFinished(); tctx->SetDead(); QuarantinePush(tctx); } where basically everything is duplicated, but is concise in each fork of IMHO both are more error-prone for future maintenance than what I wrote If there's another possibility you had in mind that gets everything right, |
lib/asan/asan_thread.cc | ||
---|---|---|
290 | What was wrong with the wrapping here? | |
lib/sanitizer_common/sanitizer_thread_registry.cc | ||
255 | What does 'aborted' refer to? | |
276 | The only reason you set detached to false here is to force SetFinished() to set status to ThreadStatusFinished, right? If so, wouldn't it be more appropriate to modify SetFinished to do this: // Comment why checking status is important. if (!detached || status == ThreadStatusCreated) status = ThreadStatusFinished; then you won't need dead and detached = false. |
lib/asan/asan_thread.cc | ||
---|---|---|
290 | It was over 79 chars, which makes an Emacs in an 80-chars-wide terminal put a \ at the end. | |
lib/sanitizer_common/sanitizer_thread_registry.cc | ||
255 | It's left over from a previous version of the change. I'll update the comment. |
lib/asan/asan_thread.h | ||
---|---|---|
71 | In common code. struct Options; // Probably don't need to define at all and pass null pointer. void Init(const Options* options = nullptr) { ... } in fuchsia code: struct AsanThread::Options { uptr stack_bottom; uptr stack_size; }; void AsanThread::SetThreadStackAndTls(const Options* options) { ... // use options.stack_bottom and options.stack_size } |
lib/asan/asan_thread.cc | ||
---|---|---|
290 | It's exactly at 80 chars limit we enforce in sanitizers, please change it back to reduce the unnecessary churn. | |
lib/sanitizer_common/sanitizer_thread_registry.cc | ||
275 | To double check, you need those never started threads to be treated the same way as detached threads, right? The reason I'm asking is if you set it here only to call SetDead/QuarantinePush later, I'd rather have a local boolean flag than changing the tctx. If there's more behind it and you need the tctx->detached set, what we have now is fine. Otherwise, sorry for the hassle, but it will be almost back to your original version, it conveys the semantics better: bool dead = tctx->detached; if (tctx->status == ThreadStatusRunning) { CHECK_GT(running_threads_, 0); running_threads_--; } else { // The thread never really existed. CHECK_EQ(tctx->status, ThreadStatusCreated); dead = true; } tctx->SetFinished(); if (dead) { tctx->SetDead(); QuarantinePush(tctx); } |
I think I've done everything requested in review.
If you are both happy with it now, please land it for me!
Thanks,
Roland
lib/asan/asan_thread.cc | ||
---|---|---|
290 | "git clang-format --style file -f origin/master" can help |
compiler-rt/trunk/lib/asan/asan_thread.cc | ||
---|---|---|
277 ↗ | (On Diff #110314) | Does it mean that there is assumption that process id = thread it? |
compiler-rt/trunk/lib/asan/asan_thread.cc | ||
---|---|---|
277 ↗ | (On Diff #110314) | Note this code is just moved around by this change (was in asan_rtl.cc), not introduced. The logic using internal_getpid() here (and earlier GetPid()) goes back many years. On Linux it is the case that the TID of the initial thread is the same as the PID, and this code does seem to assume that. |
compiler-rt/trunk/lib/asan/asan_thread.cc | ||
---|---|---|
277 ↗ | (On Diff #110314) | This is invalid assumption.. however I don't see failures on my OS (NetBSD). On NetBSD there is global PID for the process and TIDs (LWP IDs) for threads counting from 1, 2, 3... |
In common code.
in fuchsia code: