// Copyright 2013 The Flutter Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #define FML_USED_ON_EMBEDDER #include "flutter/fml/thread.h" #include #include #include #include "flutter/fml/build_config.h" #include "flutter/fml/message_loop.h" #include "flutter/fml/synchronization/waitable_event.h" #if defined(FML_OS_WIN) #include #elif defined(OS_FUCHSIA) #include #else #include #endif namespace fml { typedef std::function ThreadFunction; class ThreadHandle { public: explicit ThreadHandle(ThreadFunction&& function); ~ThreadHandle(); void Join(); private: #if defined(FML_OS_WIN) HANDLE thread_; #else pthread_t thread_; #endif }; #if defined(FML_OS_WIN) ThreadHandle::ThreadHandle(ThreadFunction&& function) { thread_ = (HANDLE*)_beginthreadex( nullptr, Thread::GetDefaultStackSize(), [](void* arg) -> unsigned { std::unique_ptr function( reinterpret_cast(arg)); (*function)(); return 0; }, new ThreadFunction(std::move(function)), 0, nullptr); FML_CHECK(thread_ != nullptr); } void ThreadHandle::Join() { WaitForSingleObjectEx(thread_, INFINITE, FALSE); } ThreadHandle::~ThreadHandle() { CloseHandle(thread_); } #else ThreadHandle::ThreadHandle(ThreadFunction&& function) { pthread_attr_t attr; pthread_attr_init(&attr); int result = pthread_attr_setstacksize(&attr, Thread::GetDefaultStackSize()); FML_CHECK(result == 0); result = pthread_create( &thread_, &attr, [](void* arg) -> void* { std::unique_ptr function( reinterpret_cast(arg)); (*function)(); return nullptr; }, new ThreadFunction(std::move(function))); FML_CHECK(result == 0); result = pthread_attr_destroy(&attr); FML_CHECK(result == 0); } void ThreadHandle::Join() { pthread_join(thread_, nullptr); } ThreadHandle::~ThreadHandle() {} #endif #if defined(FML_OS_WIN) // The information on how to set the thread name comes from // a MSDN article: http://msdn2.microsoft.com/en-us/library/xcb2z8hs.aspx const DWORD kVCThreadNameException = 0x406D1388; typedef struct tagTHREADNAME_INFO { DWORD dwType; // Must be 0x1000. LPCSTR szName; // Pointer to name (in user addr space). DWORD dwThreadID; // Thread ID (-1=caller thread). DWORD dwFlags; // Reserved for future use, must be zero. } THREADNAME_INFO; #endif void SetThreadName(const std::string& name) { if (name == "") { return; } #if defined(FML_OS_MACOSX) pthread_setname_np(name.c_str()); #elif defined(FML_OS_LINUX) || defined(FML_OS_ANDROID) // Linux thread names are limited to 16 characters including the terminating // null. constexpr std::string::size_type kLinuxMaxThreadNameLen = 15; pthread_setname_np(pthread_self(), name.substr(0, kLinuxMaxThreadNameLen).c_str()); #elif defined(FML_OS_WIN) THREADNAME_INFO info; info.dwType = 0x1000; info.szName = name.c_str(); info.dwThreadID = GetCurrentThreadId(); info.dwFlags = 0; __try { RaiseException(kVCThreadNameException, 0, sizeof(info) / sizeof(DWORD), reinterpret_cast(&info)); } __except (EXCEPTION_CONTINUE_EXECUTION) { } #elif defined(OS_FUCHSIA) zx::thread::self()->set_property(ZX_PROP_NAME, name.c_str(), name.size()); #else FML_DLOG(INFO) << "Could not set the thread name to '" << name << "' on this platform."; #endif } void Thread::SetCurrentThreadName(const Thread::ThreadConfig& config) { SetThreadName(config.name); } Thread::Thread(const std::string& name) : Thread(Thread::SetCurrentThreadName, ThreadConfig(name)) {} Thread::Thread(const ThreadConfigSetter& setter, const ThreadConfig& config) : joined_(false) { fml::AutoResetWaitableEvent latch; fml::RefPtr runner; thread_ = std::make_unique( [&latch, &runner, setter, config]() -> void { setter(config); fml::MessageLoop::EnsureInitializedForCurrentThread(); auto& loop = MessageLoop::GetCurrent(); runner = loop.GetTaskRunner(); latch.Signal(); loop.Run(); }); latch.Wait(); task_runner_ = runner; } Thread::~Thread() { Join(); } fml::RefPtr Thread::GetTaskRunner() const { return task_runner_; } void Thread::Join() { if (joined_) { return; } joined_ = true; task_runner_->PostTask([]() { MessageLoop::GetCurrent().Terminate(); }); thread_->Join(); } size_t Thread::GetDefaultStackSize() { return 1024 * 1024 * 2; } } // namespace fml