| //===-- sanitizer_thread_arg_retval.cpp -------------------------*- C++ -*-===// | 
 | // | 
 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | 
 | // See https://llvm.org/LICENSE.txt for license information. | 
 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | 
 | // | 
 | //===----------------------------------------------------------------------===// | 
 | // | 
 | // This file is shared between sanitizer tools. | 
 | // | 
 | // Tracks thread arguments and return value for leak checking. | 
 | //===----------------------------------------------------------------------===// | 
 |  | 
 | #include "sanitizer_thread_arg_retval.h" | 
 |  | 
 | #include "sanitizer_placement_new.h" | 
 |  | 
 | namespace __sanitizer { | 
 |  | 
 | void ThreadArgRetval::CreateLocked(uptr thread, bool detached, | 
 |                                    const Args& args) { | 
 |   CheckLocked(); | 
 |   Data& t = data_[thread]; | 
 |   t = {}; | 
 |   t.gen = gen_++; | 
 |   static_assert(sizeof(gen_) == sizeof(u32) && kInvalidGen == UINT32_MAX); | 
 |   if (gen_ == kInvalidGen) | 
 |     gen_ = 0; | 
 |   t.detached = detached; | 
 |   t.args = args; | 
 | } | 
 |  | 
 | ThreadArgRetval::Args ThreadArgRetval::GetArgs(uptr thread) const { | 
 |   __sanitizer::Lock lock(&mtx_); | 
 |   auto t = data_.find(thread); | 
 |   CHECK(t); | 
 |   if (t->second.done) | 
 |     return {}; | 
 |   return t->second.args; | 
 | } | 
 |  | 
 | void ThreadArgRetval::Finish(uptr thread, void* retval) { | 
 |   __sanitizer::Lock lock(&mtx_); | 
 |   auto t = data_.find(thread); | 
 |   if (!t) | 
 |     return; | 
 |   if (t->second.detached) { | 
 |     // Retval of detached thread connot be retrieved. | 
 |     data_.erase(t); | 
 |     return; | 
 |   } | 
 |   t->second.done = true; | 
 |   t->second.args.arg_retval = retval; | 
 | } | 
 |  | 
 | u32 ThreadArgRetval::BeforeJoin(uptr thread) const { | 
 |   __sanitizer::Lock lock(&mtx_); | 
 |   auto t = data_.find(thread); | 
 |   if (t && !t->second.detached) { | 
 |     return t->second.gen; | 
 |   } | 
 |   if (!common_flags()->detect_invalid_join) | 
 |     return kInvalidGen; | 
 |   const char* reason = "unknown"; | 
 |   if (!t) { | 
 |     reason = "already joined"; | 
 |   } else if (t->second.detached) { | 
 |     reason = "detached"; | 
 |   } | 
 |   Report("ERROR: %s: Joining %s thread, aborting.\n", SanitizerToolName, | 
 |          reason); | 
 |   Die(); | 
 | } | 
 |  | 
 | void ThreadArgRetval::AfterJoin(uptr thread, u32 gen) { | 
 |   __sanitizer::Lock lock(&mtx_); | 
 |   auto t = data_.find(thread); | 
 |   if (!t || gen != t->second.gen) { | 
 |     // Thread was reused and erased by any other event, or we had an invalid | 
 |     // join. | 
 |     return; | 
 |   } | 
 |   CHECK(!t->second.detached); | 
 |   data_.erase(t); | 
 | } | 
 |  | 
 | void ThreadArgRetval::DetachLocked(uptr thread) { | 
 |   CheckLocked(); | 
 |   auto t = data_.find(thread); | 
 |   CHECK(t); | 
 |   CHECK(!t->second.detached); | 
 |   if (t->second.done) { | 
 |     // We can't retrive retval after detached thread finished. | 
 |     data_.erase(t); | 
 |     return; | 
 |   } | 
 |   t->second.detached = true; | 
 | } | 
 |  | 
 | void ThreadArgRetval::GetAllPtrsLocked(InternalMmapVector<uptr>* ptrs) { | 
 |   CheckLocked(); | 
 |   CHECK(ptrs); | 
 |   data_.forEach([&](DenseMap<uptr, Data>::value_type& kv) -> bool { | 
 |     ptrs->push_back((uptr)kv.second.args.arg_retval); | 
 |     return true; | 
 |   }); | 
 | } | 
 |  | 
 | }  // namespace __sanitizer |