sanitizer_thread_arg_retval.h 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117
  1. //===-- sanitizer_thread_arg_retval.h ---------------------------*- C++ -*-===//
  2. //
  3. // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
  4. // See https://llvm.org/LICENSE.txt for license information.
  5. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  6. //
  7. //===----------------------------------------------------------------------===//
  8. //
  9. // This file is shared between sanitizer tools.
  10. //
  11. // Tracks thread arguments and return value for leak checking.
  12. //===----------------------------------------------------------------------===//
  13. #ifndef SANITIZER_THREAD_ARG_RETVAL_H
  14. #define SANITIZER_THREAD_ARG_RETVAL_H
  15. #include "sanitizer_common.h"
  16. #include "sanitizer_dense_map.h"
  17. #include "sanitizer_list.h"
  18. #include "sanitizer_mutex.h"
  19. namespace __sanitizer {
  20. // Primary goal of the class is to keep alive arg and retval pointer for leak
  21. // checking. However it can be used to pass those pointer into wrappers used by
  22. // interceptors. The difference from ThreadRegistry/ThreadList is that this
  23. // class keeps data up to the detach or join, as exited thread still can be
  24. // joined to retrive retval. ThreadRegistry/ThreadList can discard exited
  25. // threads immediately.
  26. class SANITIZER_MUTEX ThreadArgRetval {
  27. public:
  28. struct Args {
  29. void* (*routine)(void*);
  30. void* arg_retval; // Either arg or retval.
  31. };
  32. void Lock() SANITIZER_ACQUIRE() { mtx_.Lock(); }
  33. void CheckLocked() const SANITIZER_CHECK_LOCKED() { mtx_.CheckLocked(); }
  34. void Unlock() SANITIZER_RELEASE() { mtx_.Unlock(); }
  35. // Wraps pthread_create or similar. We need to keep object locked, to
  36. // prevent child thread from proceeding without thread handle.
  37. template <typename CreateFn /* returns thread id on success, or 0 */>
  38. void Create(bool detached, const Args& args, const CreateFn& fn) {
  39. // No need to track detached threads with no args, but we will to do as it's
  40. // not expensive and less edge-cases.
  41. __sanitizer::Lock lock(&mtx_);
  42. if (uptr thread = fn())
  43. CreateLocked(thread, detached, args);
  44. }
  45. // Returns thread arg and routine.
  46. Args GetArgs(uptr thread) const;
  47. // Mark thread as done and stores retval or remove if detached. Should be
  48. // called by the thread.
  49. void Finish(uptr thread, void* retval);
  50. // Mark thread as detached or remove if done.
  51. template <typename DetachFn /* returns true on success */>
  52. void Detach(uptr thread, const DetachFn& fn) {
  53. // Lock to prevent re-use of the thread between fn() and DetachLocked()
  54. // calls.
  55. __sanitizer::Lock lock(&mtx_);
  56. if (fn())
  57. DetachLocked(thread);
  58. }
  59. // Joins the thread.
  60. template <typename JoinFn /* returns true on success */>
  61. void Join(uptr thread, const JoinFn& fn) {
  62. // Remember internal id of the thread to prevent re-use of the thread
  63. // between fn() and AfterJoin() calls. Locking JoinFn, like in
  64. // Detach(), implementation can cause deadlock.
  65. auto gen = BeforeJoin(thread);
  66. if (fn())
  67. AfterJoin(thread, gen);
  68. }
  69. // Returns all arg and retval which are considered alive.
  70. void GetAllPtrsLocked(InternalMmapVector<uptr>* ptrs);
  71. uptr size() const {
  72. __sanitizer::Lock lock(&mtx_);
  73. return data_.size();
  74. }
  75. // FIXME: Add fork support. Expected users of the class are sloppy with forks
  76. // anyway. We likely should lock/unlock the object to avoid deadlocks, and
  77. // erase all but the current threads, so we can detect leaked arg or retval in
  78. // child process.
  79. // FIXME: Add cancelation support. Now if a thread was canceled, the class
  80. // will keep pointers alive forever, missing leaks caused by cancelation.
  81. private:
  82. static const u32 kInvalidGen = UINT32_MAX;
  83. struct Data {
  84. Args args;
  85. u32 gen; // Avoid collision if thread id re-used.
  86. bool detached;
  87. bool done;
  88. };
  89. void CreateLocked(uptr thread, bool detached, const Args& args);
  90. u32 BeforeJoin(uptr thread) const;
  91. void AfterJoin(uptr thread, u32 gen);
  92. void DetachLocked(uptr thread);
  93. mutable Mutex mtx_;
  94. DenseMap<uptr, Data> data_;
  95. u32 gen_ = 0;
  96. };
  97. } // namespace __sanitizer
  98. #endif // SANITIZER_THREAD_ARG_RETVAL_H