1 | // Copyright 2013 The Flutter Authors. All rights reserved. |
2 | // Use of this source code is governed by a BSD-style license that can be |
3 | // found in the LICENSE file. |
4 | |
5 | // A class for checking that the current thread is/isn't the same as an initial |
6 | // thread. |
7 | |
8 | #ifndef FLUTTER_FML_MEMORY_THREAD_CHECKER_H_ |
9 | #define FLUTTER_FML_MEMORY_THREAD_CHECKER_H_ |
10 | |
11 | #include "flutter/fml/build_config.h" |
12 | |
13 | #if defined(OS_WIN) |
14 | #include <windows.h> |
15 | #else |
16 | #include <pthread.h> |
17 | #endif |
18 | |
19 | #include "flutter/fml/logging.h" |
20 | #include "flutter/fml/macros.h" |
21 | |
22 | namespace fml { |
23 | |
24 | // A simple class that records the identity of the thread that it was created |
25 | // on, and at later points can tell if the current thread is the same as its |
26 | // creation thread. This class is thread-safe. |
27 | // |
28 | // Note: Unlike Chromium's |base::ThreadChecker|, this is *not* Debug-only (so |
29 | // #ifdef it out if you want something Debug-only). (Rationale: Having a |
30 | // |CalledOnValidThread()| that lies in Release builds seems bad. Moreover, |
31 | // there's a small space cost to having even an empty class. ) |
32 | class ThreadChecker final { |
33 | public: |
34 | #if defined(OS_WIN) |
35 | ThreadChecker() : self_(GetCurrentThreadId()) {} |
36 | ~ThreadChecker() {} |
37 | |
38 | bool IsCreationThreadCurrent() const { return GetCurrentThreadId() == self_; } |
39 | |
40 | private: |
41 | DWORD self_; |
42 | |
43 | #else |
44 | ThreadChecker() : self_(pthread_self()) {} |
45 | ~ThreadChecker() {} |
46 | |
47 | // Returns true if the current thread is the thread this object was created |
48 | // on and false otherwise. |
49 | bool IsCreationThreadCurrent() const { |
50 | pthread_t current_thread = pthread_self(); |
51 | bool is_creation_thread_current = !!pthread_equal(current_thread, self_); |
52 | #ifdef __APPLE__ |
53 | // TODO(https://github.com/flutter/flutter/issues/45272): Implement for |
54 | // other platforms. |
55 | if (!is_creation_thread_current) { |
56 | static const int buffer_length = 128; |
57 | char expected_thread[buffer_length]; |
58 | char actual_thread[buffer_length]; |
59 | if (0 == pthread_getname_np(current_thread, actual_thread, |
60 | buffer_length) && |
61 | 0 == pthread_getname_np(self_, actual_thread, buffer_length)) { |
62 | FML_DLOG(ERROR) << "IsCreationThreadCurrent expected thread: '" |
63 | << expected_thread << "' actual thread:'" |
64 | << actual_thread << "'" ; |
65 | } |
66 | } |
67 | #endif // __APPLE__ |
68 | return is_creation_thread_current; |
69 | } |
70 | |
71 | private: |
72 | pthread_t self_; |
73 | #endif |
74 | }; |
75 | |
76 | #if !defined(NDEBUG) |
77 | #define FML_DECLARE_THREAD_CHECKER(c) fml::ThreadChecker c |
78 | #define FML_DCHECK_CREATION_THREAD_IS_CURRENT(c) \ |
79 | FML_DCHECK((c).IsCreationThreadCurrent()) |
80 | #else |
81 | #define FML_DECLARE_THREAD_CHECKER(c) |
82 | #define FML_DCHECK_CREATION_THREAD_IS_CURRENT(c) ((void)0) |
83 | #endif |
84 | |
85 | } // namespace fml |
86 | |
87 | #endif // FLUTTER_FML_MEMORY_THREAD_CHECKER_H_ |
88 | |