This source file includes following definitions.
- CreateComInitializer
- CreateWithType
- Create
- CreateWithLoopAndComInitTypes
- was_quit_properly_
- joiner_
- StartWithType
- SetComInitType
- QuitThread
- JoinAndDeleteThread
- ThreadMain
#include "remoting/base/auto_thread.h"
#include "base/bind.h"
#include "base/lazy_instance.h"
#include "base/third_party/dynamic_annotations/dynamic_annotations.h"
#include "base/threading/thread_local.h"
#include "base/threading/thread_restrictions.h"
#include "base/synchronization/waitable_event.h"
#include "remoting/base/auto_thread_task_runner.h"
#if defined(OS_WIN)
#include "base/win/scoped_com_initializer.h"
#endif
namespace remoting {
namespace {
#if defined(OS_WIN)
scoped_ptr<base::win::ScopedCOMInitializer> CreateComInitializer(
AutoThread::ComInitType type) {
scoped_ptr<base::win::ScopedCOMInitializer> initializer;
if (type == AutoThread::COM_INIT_MTA) {
initializer.reset(new base::win::ScopedCOMInitializer(
base::win::ScopedCOMInitializer::kMTA));
} else if (type == AutoThread::COM_INIT_STA) {
initializer.reset(new base::win::ScopedCOMInitializer());
}
return initializer.Pass();
}
#endif
}
struct AutoThread::StartupData {
base::MessageLoop::Type loop_type;
scoped_refptr<AutoThreadTaskRunner> task_runner;
base::WaitableEvent event;
explicit StartupData(base::MessageLoop::Type type)
: loop_type(type), event(false, false) {}
};
scoped_refptr<AutoThreadTaskRunner> AutoThread::CreateWithType(
const char* name,
scoped_refptr<AutoThreadTaskRunner> joiner,
base::MessageLoop::Type type) {
AutoThread* thread = new AutoThread(name, joiner.get());
scoped_refptr<AutoThreadTaskRunner> task_runner = thread->StartWithType(type);
if (!task_runner.get())
delete thread;
return task_runner;
}
scoped_refptr<AutoThreadTaskRunner> AutoThread::Create(
const char* name, scoped_refptr<AutoThreadTaskRunner> joiner) {
return CreateWithType(name, joiner, base::MessageLoop::TYPE_DEFAULT);
}
#if defined(OS_WIN)
scoped_refptr<AutoThreadTaskRunner> AutoThread::CreateWithLoopAndComInitTypes(
const char* name,
scoped_refptr<AutoThreadTaskRunner> joiner,
base::MessageLoop::Type loop_type,
ComInitType com_init_type) {
AutoThread* thread = new AutoThread(name, joiner);
thread->SetComInitType(com_init_type);
scoped_refptr<AutoThreadTaskRunner> task_runner =
thread->StartWithType(loop_type);
if (!task_runner)
delete thread;
return task_runner;
}
#endif
AutoThread::AutoThread(const char* name)
: startup_data_(NULL),
#if defined(OS_WIN)
com_init_type_(COM_INIT_NONE),
#endif
thread_(),
name_(name),
was_quit_properly_(false) {
}
AutoThread::AutoThread(const char* name, AutoThreadTaskRunner* joiner)
: startup_data_(NULL),
#if defined(OS_WIN)
com_init_type_(COM_INIT_NONE),
#endif
thread_(),
name_(name),
was_quit_properly_(false),
joiner_(joiner) {
}
AutoThread::~AutoThread() {
DCHECK(!startup_data_);
if (!thread_.is_null()) {
base::PlatformThread::Join(thread_);
}
}
scoped_refptr<AutoThreadTaskRunner> AutoThread::StartWithType(
base::MessageLoop::Type type) {
DCHECK(thread_.is_null());
#if defined(OS_WIN)
DCHECK(com_init_type_ != COM_INIT_STA || type == base::MessageLoop::TYPE_UI);
#endif
StartupData startup_data(type);
startup_data_ = &startup_data;
if (!base::PlatformThread::Create(0, this, &thread_)) {
DLOG(ERROR) << "failed to create thread";
startup_data_ = NULL;
return NULL;
}
base::ThreadRestrictions::ScopedAllowWait allow_wait;
startup_data.event.Wait();
startup_data_ = NULL;
DCHECK(startup_data.task_runner.get());
return startup_data.task_runner;
}
#if defined(OS_WIN)
void AutoThread::SetComInitType(ComInitType com_init_type) {
DCHECK_EQ(com_init_type_, COM_INIT_NONE);
com_init_type_ = com_init_type;
}
#endif
void AutoThread::QuitThread(
scoped_refptr<base::SingleThreadTaskRunner> task_runner) {
if (!task_runner->BelongsToCurrentThread()) {
task_runner->PostTask(FROM_HERE, base::Bind(&AutoThread::QuitThread,
base::Unretained(this),
task_runner));
return;
}
base::MessageLoop::current()->Quit();
was_quit_properly_ = true;
if (joiner_.get()) {
joiner_->PostTask(
FROM_HERE,
base::Bind(&AutoThread::JoinAndDeleteThread, base::Unretained(this)));
}
}
void AutoThread::JoinAndDeleteThread() {
delete this;
}
void AutoThread::ThreadMain() {
base::MessageLoop message_loop(startup_data_->loop_type);
base::PlatformThread::SetName(name_.c_str());
ANNOTATE_THREAD_NAME(name_.c_str());
message_loop.set_thread_name(name_);
startup_data_->task_runner =
new AutoThreadTaskRunner(message_loop.message_loop_proxy(),
base::Bind(&AutoThread::QuitThread,
base::Unretained(this),
message_loop.message_loop_proxy()));
startup_data_->event.Signal();
#if defined(OS_WIN)
scoped_ptr<base::win::ScopedCOMInitializer> com_initializer(
CreateComInitializer(com_init_type_));
#endif
message_loop.Run();
DCHECK(was_quit_properly_);
}
}