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
25namespace fml {
26
27Thread::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
42Thread::~Thread() {
43 Join();
44}
45
46fml::RefPtr<fml::TaskRunner> Thread::GetTaskRunner() const {
47 return task_runner_;
48}
49
50void 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
62const DWORD kVCThreadNameException = 0x406D1388;
63typedef 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
71void 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