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