1 //===-- sanitizer_thread_arg_retval.h ---------------------------*- C++ -*-===//
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
7 //===----------------------------------------------------------------------===//
9 // This file is shared between sanitizer tools.
11 // Tracks thread arguments and return value for leak checking.
12 //===----------------------------------------------------------------------===//
14 #ifndef SANITIZER_THREAD_ARG_RETVAL_H
15 #define SANITIZER_THREAD_ARG_RETVAL_H
17 #include "sanitizer_common.h"
18 #include "sanitizer_dense_map.h"
19 #include "sanitizer_list.h"
20 #include "sanitizer_mutex.h"
22 namespace __sanitizer
{
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.
30 class SANITIZER_MUTEX ThreadArgRetval
{
33 void* (*routine
)(void*);
34 void* arg_retval
; // Either arg or retval.
36 void Lock() SANITIZER_ACQUIRE() { mtx_
.Lock(); }
37 void CheckLocked() const SANITIZER_CHECK_LOCKED() { mtx_
.CheckLocked(); }
38 void Unlock() SANITIZER_RELEASE() { mtx_
.Unlock(); }
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
);
51 // Returns thread arg and routine.
52 Args
GetArgs(uptr thread
) const;
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
);
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()
63 __sanitizer::Lock
lock(&mtx_
);
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
);
76 AfterJoin(thread
, gen
);
79 // Returns all arg and retval which are considered alive.
80 void GetAllPtrsLocked(InternalMmapVector
<uptr
>* ptrs
);
83 __sanitizer::Lock
lock(&mtx_
);
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
92 // FIXME: Add cancelation support. Now if a thread was canceled, the class
93 // will keep pointers alive forever, missing leaks caused by cancelation.
96 static const u32 kInvalidGen
= UINT32_MAX
;
99 u32 gen
; // Avoid collision if thread id re-used.
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
);
111 DenseMap
<uptr
, Data
> data_
;
115 } // namespace __sanitizer
117 #endif // SANITIZER_THREAD_ARG_RETVAL_H