|  | // 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. | 
|  |  | 
|  | #include "flutter/fml/thread.h" | 
|  |  | 
|  | #if defined(FML_OS_MACOSX) || defined(FML_OS_LINUX) || defined(FML_OS_ANDROID) | 
|  | #define FLUTTER_PTHREAD_SUPPORTED 1 | 
|  | #else | 
|  | #define FLUTTER_PTHREAD_SUPPORTED 0 | 
|  | #endif | 
|  |  | 
|  | #if FLUTTER_PTHREAD_SUPPORTED | 
|  | #include <pthread.h> | 
|  | #else | 
|  | #endif | 
|  |  | 
|  | #include <memory> | 
|  | #include "gtest/gtest.h" | 
|  |  | 
|  | TEST(Thread, CanStartAndEnd) { | 
|  | fml::Thread thread; | 
|  | ASSERT_TRUE(thread.GetTaskRunner()); | 
|  | } | 
|  |  | 
|  | TEST(Thread, CanStartAndEndWithExplicitJoin) { | 
|  | fml::Thread thread; | 
|  | ASSERT_TRUE(thread.GetTaskRunner()); | 
|  | thread.Join(); | 
|  | } | 
|  |  | 
|  | TEST(Thread, HasARunningMessageLoop) { | 
|  | fml::Thread thread; | 
|  | bool done = false; | 
|  | thread.GetTaskRunner()->PostTask([&done]() { done = true; }); | 
|  | thread.Join(); | 
|  | ASSERT_TRUE(done); | 
|  | } | 
|  |  | 
|  | #if FLUTTER_PTHREAD_SUPPORTED | 
|  | TEST(Thread, ThreadNameCreatedWithConfig) { | 
|  | const std::string name = "Thread1"; | 
|  | fml::Thread thread(name); | 
|  |  | 
|  | bool done = false; | 
|  | thread.GetTaskRunner()->PostTask([&done, &name]() { | 
|  | done = true; | 
|  | char thread_name[8]; | 
|  | pthread_t current_thread = pthread_self(); | 
|  | pthread_getname_np(current_thread, thread_name, 8); | 
|  | ASSERT_EQ(thread_name, name); | 
|  | }); | 
|  | thread.Join(); | 
|  | ASSERT_TRUE(done); | 
|  | } | 
|  |  | 
|  | static void MockThreadConfigSetter(const fml::Thread::ThreadConfig& config) { | 
|  | // set thread name | 
|  | fml::Thread::SetCurrentThreadName(config); | 
|  |  | 
|  | pthread_t tid = pthread_self(); | 
|  | struct sched_param param; | 
|  | int policy = SCHED_OTHER; | 
|  | switch (config.priority) { | 
|  | case fml::Thread::ThreadPriority::DISPLAY: | 
|  | param.sched_priority = 10; | 
|  | break; | 
|  | default: | 
|  | param.sched_priority = 1; | 
|  | } | 
|  | pthread_setschedparam(tid, policy, ¶m); | 
|  | } | 
|  |  | 
|  | TEST(Thread, ThreadPriorityCreatedWithConfig) { | 
|  | const std::string thread1_name = "Thread1"; | 
|  | const std::string thread2_name = "Thread2"; | 
|  |  | 
|  | fml::Thread thread(MockThreadConfigSetter, | 
|  | fml::Thread::ThreadConfig( | 
|  | thread1_name, fml::Thread::ThreadPriority::NORMAL)); | 
|  | bool done = false; | 
|  |  | 
|  | struct sched_param param; | 
|  | int policy; | 
|  | thread.GetTaskRunner()->PostTask([&]() { | 
|  | done = true; | 
|  | char thread_name[8]; | 
|  | pthread_t current_thread = pthread_self(); | 
|  | pthread_getname_np(current_thread, thread_name, 8); | 
|  | pthread_getschedparam(current_thread, &policy, ¶m); | 
|  | ASSERT_EQ(thread_name, thread1_name); | 
|  | ASSERT_EQ(policy, SCHED_OTHER); | 
|  | ASSERT_EQ(param.sched_priority, 1); | 
|  | }); | 
|  |  | 
|  | fml::Thread thread2(MockThreadConfigSetter, | 
|  | fml::Thread::ThreadConfig( | 
|  | thread2_name, fml::Thread::ThreadPriority::DISPLAY)); | 
|  | thread2.GetTaskRunner()->PostTask([&]() { | 
|  | done = true; | 
|  | char thread_name[8]; | 
|  | pthread_t current_thread = pthread_self(); | 
|  | pthread_getname_np(current_thread, thread_name, 8); | 
|  | pthread_getschedparam(current_thread, &policy, ¶m); | 
|  | ASSERT_EQ(thread_name, thread2_name); | 
|  | ASSERT_EQ(policy, SCHED_OTHER); | 
|  | ASSERT_EQ(param.sched_priority, 10); | 
|  | }); | 
|  | thread.Join(); | 
|  | ASSERT_TRUE(done); | 
|  | } | 
|  | #endif |