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 | #define FML_USED_ON_EMBEDDER |
6 | |
7 | #include "flutter/fml/thread.h" |
8 | |
9 | #include "flutter/fml/build_config.h" |
10 | |
11 | #if defined(OS_WIN) |
12 | #include <windows.h> |
13 | #elif defined(OS_FUCHSIA) |
14 | #include <lib/zx/thread.h> |
15 | #else |
16 | #include <pthread.h> |
17 | #endif |
18 | |
19 | #include <memory> |
20 | #include <string> |
21 | |
22 | #include "flutter/fml/message_loop.h" |
23 | #include "flutter/fml/synchronization/waitable_event.h" |
24 | |
25 | namespace fml { |
26 | |
27 | Thread::Thread(const std::string& name) : joined_(false) { |
28 | fml::AutoResetWaitableEvent latch; |
29 | fml::RefPtr<fml::TaskRunner> runner; |
30 | thread_ = std::make_unique<std::thread>([&latch, &runner, name]() -> void { |
31 | SetCurrentThreadName(name); |
32 | fml::MessageLoop::EnsureInitializedForCurrentThread(); |
33 | auto& loop = MessageLoop::GetCurrent(); |
34 | runner = loop.GetTaskRunner(); |
35 | latch.Signal(); |
36 | loop.Run(); |
37 | }); |
38 | latch.Wait(); |
39 | task_runner_ = runner; |
40 | } |
41 | |
42 | Thread::~Thread() { |
43 | Join(); |
44 | } |
45 | |
46 | fml::RefPtr<fml::TaskRunner> Thread::GetTaskRunner() const { |
47 | return task_runner_; |
48 | } |
49 | |
50 | void Thread::Join() { |
51 | if (joined_) { |
52 | return; |
53 | } |
54 | joined_ = true; |
55 | task_runner_->PostTask([]() { MessageLoop::GetCurrent().Terminate(); }); |
56 | thread_->join(); |
57 | } |
58 | |
59 | #if defined(OS_WIN) |
60 | // The information on how to set the thread name comes from |
61 | // a MSDN article: http://msdn2.microsoft.com/en-us/library/xcb2z8hs.aspx |
62 | const DWORD kVCThreadNameException = 0x406D1388; |
63 | typedef struct tagTHREADNAME_INFO { |
64 | DWORD dwType; // Must be 0x1000. |
65 | LPCSTR szName; // Pointer to name (in user addr space). |
66 | DWORD dwThreadID; // Thread ID (-1=caller thread). |
67 | DWORD dwFlags; // Reserved for future use, must be zero. |
68 | } THREADNAME_INFO; |
69 | #endif |
70 | |
71 | void Thread::SetCurrentThreadName(const std::string& name) { |
72 | if (name == "") { |
73 | return; |
74 | } |
75 | #if defined(OS_MACOSX) |
76 | pthread_setname_np(name.c_str()); |
77 | #elif defined(OS_LINUX) || defined(OS_ANDROID) |
78 | pthread_setname_np(pthread_self(), name.c_str()); |
79 | #elif defined(OS_WIN) |
80 | THREADNAME_INFO info; |
81 | info.dwType = 0x1000; |
82 | info.szName = name.c_str(); |
83 | info.dwThreadID = GetCurrentThreadId(); |
84 | info.dwFlags = 0; |
85 | __try { |
86 | RaiseException(kVCThreadNameException, 0, sizeof(info) / sizeof(DWORD), |
87 | reinterpret_cast<DWORD_PTR*>(&info)); |
88 | } __except (EXCEPTION_CONTINUE_EXECUTION) { |
89 | } |
90 | #elif defined(OS_FUCHSIA) |
91 | zx::thread::self()->set_property(ZX_PROP_NAME, name.c_str(), name.size()); |
92 | #else |
93 | FML_DLOG(INFO) << "Could not set the thread name to '"<< name |
94 | << "' on this platform."; |
95 | #endif |
96 | } |
97 | |
98 | } // namespace fml |
99 |