brintos

brintos / llvm-project-archived public Read only

0
0
Text · 4.0 KiB · 0e6d351 Raw
118 lines · c
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-exception6//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_H15#define SANITIZER_THREAD_ARG_RETVAL_H16 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 leak25// checking. However it can be used to pass those pointer into wrappers used by26// interceptors. The difference from ThreadRegistry/ThreadList is that this27// class keeps data up to the detach or join, as exited thread still can be28// joined to retrive retval. ThreadRegistry/ThreadList can discard exited29// 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, to41  // 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's45    // 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 be55  // 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 thread72    // between fn() and AfterJoin() calls. Locking JoinFn, like in73    // 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 forks88  // anyway. We likely should lock/unlock the object to avoid deadlocks, and89  // erase all but the current threads, so we can detect leaked arg or retval in90  // child process.91 92  // FIXME: Add cancelation support. Now if a thread was canceled, the class93  // 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 __sanitizer116 117#endif  // SANITIZER_THREAD_ARG_RETVAL_H118