diff --git a/fml/BUILD.gn b/fml/BUILD.gn index 0713ddab2419be0a23a531d230bdea67e1a3698b..6d66faaa803c6a3ce768655ae18d5631c34244c9 100644 --- a/fml/BUILD.gn +++ b/fml/BUILD.gn @@ -90,6 +90,13 @@ source_set("fml") { "platform/linux/timerfd.h", ] } + + if (is_win) { + sources += [ + "platform/win/message_loop_win.cc", + "platform/win/message_loop_win.h", + ] + } } executable("fml_unittests") { diff --git a/fml/message_loop_impl.cc b/fml/message_loop_impl.cc index 9a3b4c003b7a7ea95d79325ffb151046f1eb349a..ee39dc9d876bc7d84850e815125fbed91ff9ffdf 100644 --- a/fml/message_loop_impl.cc +++ b/fml/message_loop_impl.cc @@ -25,6 +25,11 @@ using PlatformMessageLoopImpl = fml::MessageLoopAndroid; #include "flutter/fml/platform/linux/message_loop_linux.h" using PlatformMessageLoopImpl = fml::MessageLoopLinux; +#elif OS_WIN + +#include "flutter/fml/platform/win/message_loop_win.h" +using PlatformMessageLoopImpl = fml::MessageLoopWin; + #else #error This platform does not have a message loop implementation. diff --git a/fml/message_loop_unittests.cc b/fml/message_loop_unittests.cc index 1b366913152847c97789116b55bfdfe6dc8554f1..cee71e716a2a4caba633c5c8b286c857db90e01f 100644 --- a/fml/message_loop_unittests.cc +++ b/fml/message_loop_unittests.cc @@ -193,7 +193,7 @@ TEST(MessageLoop, TIME_SENSITIVE(MultipleDelayedTasksWithIncreasingDeltas)) { for (int target_ms = 0 + 2; target_ms < count + 2; target_ms++) { auto begin = ftl::TimePoint::Now(); loop.GetTaskRunner()->PostDelayedTask( - [begin, target_ms, &checked]() { + [begin, target_ms, &checked, count]() { auto delta = ftl::TimePoint::Now() - begin; auto ms = delta.ToMillisecondsF(); ASSERT_GE(ms, target_ms - 2); @@ -217,10 +217,10 @@ TEST(MessageLoop, TIME_SENSITIVE(MultipleDelayedTasksWithDecreasingDeltas)) { std::thread thread([&checked, count]() { fml::MessageLoop::EnsureInitializedForCurrentThread(); auto& loop = fml::MessageLoop::GetCurrent(); - for (int target_ms = count + 2; target_ms >= 0 + 2; target_ms--) { + for (int target_ms = count + 2; target_ms > 0 + 2; target_ms--) { auto begin = ftl::TimePoint::Now(); loop.GetTaskRunner()->PostDelayedTask( - [begin, target_ms, &checked]() { + [begin, target_ms, &checked, count]() { auto delta = ftl::TimePoint::Now() - begin; auto ms = delta.ToMillisecondsF(); ASSERT_GE(ms, target_ms - 2); diff --git a/fml/platform/win/message_loop_win.cc b/fml/platform/win/message_loop_win.cc new file mode 100644 index 0000000000000000000000000000000000000000..fcd5bafa4f572eb97d0342dc76a5247847e1b464 --- /dev/null +++ b/fml/platform/win/message_loop_win.cc @@ -0,0 +1,39 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "flutter/fml/platform/win/message_loop_win.h" + +namespace fml { + +MessageLoopWin::MessageLoopWin() + : timer_(CreateWaitableTimer(NULL, FALSE, NULL)) { + FTL_CHECK(timer_.is_valid()); +} + +MessageLoopWin::~MessageLoopWin() = default; + +void MessageLoopWin::Run() { + running_ = true; + + while (running_) { + FTL_CHECK(WaitForSingleObject(timer_.get(), INFINITE) == 0); + RunExpiredTasksNow(); + } +} + +void MessageLoopWin::Terminate() { + running_ = false; + WakeUp(ftl::TimePoint::Now()); +} + +void MessageLoopWin::WakeUp(ftl::TimePoint time_point) { + LARGE_INTEGER due_time = {0}; + ftl::TimePoint now = ftl::TimePoint::Now(); + if (time_point > now) { + due_time.QuadPart = (time_point - now).ToNanoseconds() / -100; + } + FTL_CHECK(SetWaitableTimer(timer_.get(), &due_time, 0, NULL, NULL, FALSE)); +} + +} // namespace fml diff --git a/fml/platform/win/message_loop_win.h b/fml/platform/win/message_loop_win.h new file mode 100644 index 0000000000000000000000000000000000000000..4bf3e91e7631a331c2a782395dcfdab342e6b6d5 --- /dev/null +++ b/fml/platform/win/message_loop_win.h @@ -0,0 +1,46 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef FLUTTER_FML_PLATFORM_WIN_MESSAGE_LOOP_WIN_H_ +#define FLUTTER_FML_PLATFORM_WIN_MESSAGE_LOOP_WIN_H_ + +#include + +#include + +#include "flutter/fml/message_loop_impl.h" +#include "lib/ftl/macros.h" +#include "lib/ftl/memory/unique_object.h" + +namespace fml { + +class MessageLoopWin : public MessageLoopImpl { + private: + struct UniqueHandleTraits { + static HANDLE InvalidValue() { return NULL; } + static bool IsValid(HANDLE value) { return value != NULL; } + static void Free(HANDLE value) { CloseHandle(value); } + }; + + bool running_; + ftl::UniqueObject timer_; + + MessageLoopWin(); + + ~MessageLoopWin() override; + + void Run() override; + + void Terminate() override; + + void WakeUp(ftl::TimePoint time_point) override; + + FRIEND_MAKE_REF_COUNTED(MessageLoopWin); + FRIEND_REF_COUNTED_THREAD_SAFE(MessageLoopWin); + FTL_DISALLOW_COPY_AND_ASSIGN(MessageLoopWin); +}; + +} // namespace fml + +#endif // FLUTTER_FML_PLATFORM_GENERIC_MESSAGE_LOOP_GENERIC_H_ diff --git a/fml/thread.cc b/fml/thread.cc index e505a46754cab30362f517e613ab7628b5bd1fd0..03147d6fb2130476b881663e585c6c4bbb76ee5e 100644 --- a/fml/thread.cc +++ b/fml/thread.cc @@ -4,13 +4,18 @@ #include "flutter/fml/thread.h" +#include "lib/ftl/build_config.h" + +#if defined(OS_WIN) +#include +#else #include +#endif #include #include #include "flutter/fml/message_loop.h" -#include "lib/ftl/build_config.h" #include "lib/ftl/synchronization/waitable_event.h" namespace fml { @@ -47,6 +52,18 @@ void Thread::Join() { thread_->join(); } +#if defined(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 Thread::SetCurrentThreadName(const std::string& name) { if (name == "") { return; @@ -55,6 +72,17 @@ void Thread::SetCurrentThreadName(const std::string& name) { pthread_setname_np(name.c_str()); #elif OS_LINUX || OS_ANDROID pthread_setname_np(pthread_self(), name.c_str()); +#elif 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) { + } #else #error Unsupported Platform #endif diff --git a/travis/licenses_golden/licenses_flutter b/travis/licenses_golden/licenses_flutter index ea299e372134086daad3ce80dc0f2a7251b8173e..fc8451dbaf436b3328587bf0ce8b73686c89338d 100644 --- a/travis/licenses_golden/licenses_flutter +++ b/travis/licenses_golden/licenses_flutter @@ -1399,6 +1399,8 @@ FILE: ../../../flutter/fml/platform/linux/message_loop_linux.h FILE: ../../../flutter/fml/platform/linux/paths_linux.cc FILE: ../../../flutter/fml/platform/linux/timerfd.cc FILE: ../../../flutter/fml/platform/linux/timerfd.h +FILE: ../../../flutter/fml/platform/win/message_loop_win.cc +FILE: ../../../flutter/fml/platform/win/message_loop_win.h FILE: ../../../flutter/fml/task_observer.h FILE: ../../../flutter/fml/task_runner.cc FILE: ../../../flutter/fml/task_runner.h