BrowserProcessSubThread

来源:互联网 发布:惊悚电影推荐知乎 编辑:程序博客网 时间:2024/06/14 12:19

BrowserProcessSubThread

chromium WinMain中说到,浏览器主进程Browser的工作线程一部分,其类是BrowserProcessSubThread数据结构,那么我们来分析一下这个类。这个类继承自BrowserThreadImpl,而后者继承BrowserThread和base::Thread。base::Thread继承PlatformThread::Delegate,我们慢慢来研究线程的管理过程。

对于BrowserProcessSubThread类,没有什么可以值得分析的,主要是分装了一下BrowserThreadImpl接口,主要的都在后者内部中。

windbg中chromium工作线程的观察

我们观察DB线程的执行堆栈,这个是创建后的线程执行过程,详细的说是某一时刻的运行过程。

0:020> kL # Child-SP          RetAddr           Call Site00 00000000`0684f648 000007fe`fdb910dc ntdll!NtWaitForSingleObject+0xa01 00000000`0684f650 000007fe`ef200e54 KERNELBASE!WaitForSingleObjectEx+0x7902 (Inline Function) --------`-------- chrome_7feef160000!base::WaitableEvent::TimedWait+0x9503 00000000`0684f6f0 000007fe`ef1edd83 chrome_7feef160000!base::MessagePumpDefault::Run+0x1c404 (Inline Function) --------`-------- chrome_7feef160000!base::MessageLoop::RunHandler+0x1505 00000000`0684f950 000007fe`ef1c4381 chrome_7feef160000!base::RunLoop::Run+0x8306 (Inline Function) --------`-------- chrome_7feef160000!base::MessageLoop::Run+0x3507 00000000`0684f9a0 000007fe`f01d8076 chrome_7feef160000!base::Thread::Run+0x4108 00000000`0684fa00 000007fe`f01d8d3e chrome_7feef160000!content::BrowserThreadImpl::DBThreadRun+0x3609 00000000`0684fb50 000007fe`ef1c46d8 chrome_7feef160000!content::BrowserThreadImpl::Run+0xca0a 00000000`0684fb80 000007fe`ef1d7e9d chrome_7feef160000!base::Thread::ThreadMain+0x3380b 00000000`0684fbf0 00000000`7714652d chrome_7feef160000!base::`anonymous namespace'::ThreadFunc+0x15d0c 00000000`0684fc60 00000000`7762c521 kernel32!BaseThreadInitThunk+0xd0d 00000000`0684fc90 00000000`00000000 ntdll!RtlUserThreadStart+0x1d

这里面,DB线程处于等待工作中,下面我们从线程的初始化,启动,运行详细的讲解线程的生命周期。

BrowserThreadImpl

CrBrowserMain,即主进程主线程名,其如下初始化自己的主线程的:

  main_thread_.reset(      new BrowserThreadImpl(BrowserThread::UI, base::MessageLoop::current()));

我们知道,这是个UI线程,线程消息循环即为当前的消息循环。

线程的初始化

BrowserThreadImpl::BrowserThreadImpl(ID identifier,                                     base::MessageLoop* message_loop)    : Thread(message_loop->thread_name()), identifier_(identifier) {  set_message_loop(message_loop);  Initialize();}void BrowserThreadImpl::Initialize() {  BrowserThreadGlobals& globals = g_globals.Get();  base::AutoLock lock(globals.lock);  DCHECK(identifier_ >= 0 && identifier_ < ID_COUNT);  DCHECK(globals.threads[identifier_] == NULL);  globals.threads[identifier_] = this;}

BrowserThreadImpl中globals管理着一批线程,至少我们知道的,Browser进程中IO,UI,DB线程都是由其管理的,so,这里就是按号入座喽。

线程的启动

bool BrowserThreadImpl::StartWithOptions(const Options& options) {  // The global thread table needs to be locked while a new thread is  // starting, as the new thread can asynchronously start touching the  // table (and other thread's message_loop).  BrowserThreadGlobals& globals = g_globals.Get();  base::AutoLock lock(globals.lock);  return Thread::StartWithOptions(options);}

果然是一个包装,这里直接使用的是base库中的Thread启动函数。启动前加锁。

base::Thread::StartWithOptions

bool Thread::StartWithOptions(const Options& options) {  DCHECK(!message_loop_);#if defined(OS_WIN)  DCHECK((com_status_ != STA) ||      (options.message_loop_type == MessageLoop::TYPE_UI));#endif  // Reset |id_| here to support restarting the thread.  id_event_.Reset();  id_ = kInvalidThreadId;  SetThreadWasQuitProperly(false);  MessageLoop::Type type = options.message_loop_type;  if (!options.message_pump_factory.is_null())    type = MessageLoop::TYPE_CUSTOM;  message_loop_timer_slack_ = options.timer_slack;  scoped_ptr<MessageLoop> message_loop = MessageLoop::CreateUnbound(      type, options.message_pump_factory);  message_loop_ = message_loop.get();  start_event_.Reset();  // Hold the thread_lock_ while starting a new thread, so that we can make sure  // that thread_ is populated before the newly created thread accesses it.  {    AutoLock lock(thread_lock_);    if (!PlatformThread::CreateWithPriority(options.stack_size, this, &thread_,                                            options.priority)) {      DLOG(ERROR) << "failed to create thread";      message_loop_ = nullptr;      return false;    }  }  // The ownership of message_loop is managemed by the newly created thread  // within the ThreadMain.  ignore_result(message_loop.release());  DCHECK(message_loop_);  return true;}

这个函数式base thread 参数启动函数,启动前创建消息循环,使用平台类型的接口创建对应平台的线程,PlatformThread::CreateWithPriority。

base::CreateThreadInternal

// CreateThreadInternal() matches PlatformThread::CreateWithPriority(), except// that |out_thread_handle| may be nullptr, in which case a non-joinable thread// is created.bool CreateThreadInternal(size_t stack_size,                          PlatformThread::Delegate* delegate,                          PlatformThreadHandle* out_thread_handle,                          ThreadPriority priority) {  unsigned int flags = 0;  if (stack_size > 0 && base::win::GetVersion() >= base::win::VERSION_XP) {    flags = STACK_SIZE_PARAM_IS_A_RESERVATION;  } else {    stack_size = 0;  }  ThreadParams* params = new ThreadParams;  params->delegate = delegate;  params->joinable = out_thread_handle != nullptr;  params->priority = priority;  // Using CreateThread here vs _beginthreadex makes thread creation a bit  // faster and doesn't require the loader lock to be available.  Our code will  // have to work running on CreateThread() threads anyway, since we run code  // on the Windows thread pool, etc.  For some background on the difference:  //   http://www.microsoft.com/msj/1099/win32/win321099.aspx  void* thread_handle =      ::CreateThread(nullptr, stack_size, ThreadFunc, params, flags, nullptr);  if (!thread_handle) {    delete params;    return false;  }  if (out_thread_handle)    *out_thread_handle = PlatformThreadHandle(thread_handle);  else    CloseHandle(thread_handle);  return true;}

CreateThread,我们好熟悉吧,这是windows平台的线程创建接口,我们可以看到这里面传递了参数,其中一个很重要的delegate就是创建线程Thread的this指针。

base::`anonymous namespace’::ThreadFunc

DWORD __stdcall ThreadFunc(void* params) {  ThreadParams* thread_params = static_cast<ThreadParams*>(params);  PlatformThread::Delegate* delegate = thread_params->delegate;  if (!thread_params->joinable)    base::ThreadRestrictions::SetSingletonAllowed(false);  if (thread_params->priority != ThreadPriority::NORMAL)    PlatformThread::SetCurrentThreadPriority(thread_params->priority);  // Retrieve a copy of the thread handle to use as the key in the  // thread name mapping.  PlatformThreadHandle::Handle platform_handle;  BOOL did_dup = DuplicateHandle(GetCurrentProcess(),                                GetCurrentThread(),                                GetCurrentProcess(),                                &platform_handle,                                0,                                FALSE,                                DUPLICATE_SAME_ACCESS);  win::ScopedHandle scoped_platform_handle;  if (did_dup) {    scoped_platform_handle.Set(platform_handle);    ThreadIdNameManager::GetInstance()->RegisterThread(        scoped_platform_handle.Get(),        PlatformThread::CurrentId());  }  delete thread_params;  delegate->ThreadMain();  if (did_dup) {    ThreadIdNameManager::GetInstance()->RemoveName(        scoped_platform_handle.Get(),        PlatformThread::CurrentId());  }  return 0;}

这是一个线程的入口函数,windows最先执行的就是这个函数,函数设置了线程优先级,然后执行我们的线程主函数ThreadMain,而这个函数由继承Delegate类的线程具体的实现,而我们的BrowserProcessSubThread继承自Thread,其主要来实现这个ThreadMain接口,所以线程的执行权交由Thread::ThreadMain具体来执行。

Thread::ThreadMain

void Thread::ThreadMain() {  // First, make GetThreadId() available to avoid deadlocks. It could be called  // any place in the following thread initialization code.  id_ = PlatformThread::CurrentId();  DCHECK_NE(kInvalidThreadId, id_);  id_event_.Signal();  // Complete the initialization of our Thread object.  PlatformThread::SetName(name_.c_str());  ANNOTATE_THREAD_NAME(name_.c_str());  // Tell the name to race detector.  // Lazily initialize the message_loop so that it can run on this thread.  DCHECK(message_loop_);  scoped_ptr<MessageLoop> message_loop(message_loop_);  message_loop_->BindToCurrentThread();  message_loop_->set_thread_name(name_);  message_loop_->SetTimerSlack(message_loop_timer_slack_);#if defined(OS_WIN)  scoped_ptr<win::ScopedCOMInitializer> com_initializer;  if (com_status_ != NONE) {    com_initializer.reset((com_status_ == STA) ?        new win::ScopedCOMInitializer() :        new win::ScopedCOMInitializer(win::ScopedCOMInitializer::kMTA));  }#endif  // Let the thread do extra initialization.  Init();  {    AutoLock lock(running_lock_);    running_ = true;  }  start_event_.Signal();  Run(message_loop_);  {    AutoLock lock(running_lock_);    running_ = false;  }  // Let the thread do extra cleanup.  CleanUp();#if defined(OS_WIN)  com_initializer.reset();#endif  if (message_loop->type() != MessageLoop::TYPE_CUSTOM) {    // Assert that MessageLoop::QuitWhenIdle was called by ThreadQuitHelper.    // Don't check for custom message pumps, because their shutdown might not    // allow this.    DCHECK(GetThreadWasQuitProperly());  }  // We can't receive messages anymore.  // (The message loop is destructed at the end of this block)  message_loop_ = nullptr;}

函数开始处,设置平台线程名,然后设置message_loop的相关信息。然后初始化COM,之后做额外的底层子类初始化,接着调用子类的Run函数,当Run函数执行完成后,清理数据。

线程的运行

我们看开始的堆栈就明白了,这时候Browser进程的工作线程已经启动起来,该工作线程执行权已经落到了BrowserThreadImpl,一个线程已经启动成功。

因为BrowserThreadImpl管理多个工作线程,不同的线程给与不同的运行入口

void BrowserThreadImpl::Run(base::MessageLoop* message_loop) {#if defined(OS_ANDROID)  // Not to reset thread name to "Thread-???" by VM, attach VM with thread name.  // Though it may create unnecessary VM thread objects, keeping thread name  // gives more benefit in debugging in the platform.  if (!thread_name().empty()) {    base::android::AttachCurrentThreadWithName(thread_name());  }#endif  BrowserThread::ID thread_id = ID_COUNT;  CHECK(GetCurrentThreadIdentifier(&thread_id));  CHECK_EQ(identifier_, thread_id);  CHECK_EQ(Thread::message_loop(), message_loop);  switch (identifier_) {    case BrowserThread::UI:      return UIThreadRun(message_loop);    case BrowserThread::DB:      return DBThreadRun(message_loop);    case BrowserThread::FILE:      return FileThreadRun(message_loop);    case BrowserThread::FILE_USER_BLOCKING:      return FileUserBlockingThreadRun(message_loop);    case BrowserThread::PROCESS_LAUNCHER:      return ProcessLauncherThreadRun(message_loop);    case BrowserThread::CACHE:      return CacheThreadRun(message_loop);    case BrowserThread::IO:      return IOThreadRun(message_loop);    case BrowserThread::ID_COUNT:      CHECK(false);  // This shouldn't actually be reached!      break;  }  // |identifier_| must be set to a valid enum value in the constructor, so it  // should be impossible to reach here.  CHECK(false);}

这里作为一个分发函数,对于不同的线程执行不同的入口,我们研究的是DB线程,走的是DB线程入口。

NOINLINE void BrowserThreadImpl::DBThreadRun(base::MessageLoop* message_loop) {  volatile int line_number = __LINE__;  Thread::Run(message_loop);  CHECK_GT(line_number, 0);}

对于DB线程来说,直接调用父类的Run函数来执行工作。

向线程投递任务

PaskTask

我们的工作线程已经初始化并且创建并且运行起来了,那么怎么向这几个Browser工作线程投递任务呢。任务的投递提供了很多的接口,用于投递不同类型的任务。

  static bool PostTask(ID identifier,                       const tracked_objects::Location& from_here,                       const base::Closure& task);  static bool PostDelayedTask(ID identifier,                              const tracked_objects::Location& from_here,                              const base::Closure& task,                              base::TimeDelta delay);  static bool PostNonNestableTask(ID identifier,                                  const tracked_objects::Location& from_here,                                  const base::Closure& task);                                    static bool PostNonNestableDelayedTask(    .......    // staticbool BrowserThread::PostTask(ID identifier,                             const tracked_objects::Location& from_here,                             const base::Closure& task) {  return BrowserThreadImpl::PostTaskHelper(      identifier, from_here, task, base::TimeDelta(), true);}

对于Browser进程的工作线程来说,任务的投递有个帮助入口,这个入口主要是区分具体的投递对象,还是那句话,因为BrowserThreadImpl管理着好几个工作线程。

PostTaskHelper

// staticbool BrowserThreadImpl::PostTaskHelper(    BrowserThread::ID identifier,    const tracked_objects::Location& from_here,    const base::Closure& task,    base::TimeDelta delay,    bool nestable) {  DCHECK(identifier >= 0 && identifier < ID_COUNT);  // Optimization: to avoid unnecessary locks, we listed the ID enumeration in  // order of lifetime.  So no need to lock if we know that the target thread  // outlives current thread.  // Note: since the array is so small, ok to loop instead of creating a map,  // which would require a lock because std::map isn't thread safe, defeating  // the whole purpose of this optimization.  BrowserThread::ID current_thread = ID_COUNT;  bool target_thread_outlives_current =      GetCurrentThreadIdentifier(&current_thread) &&      current_thread >= identifier;  BrowserThreadGlobals& globals = g_globals.Get();  if (!target_thread_outlives_current)    globals.lock.Acquire();  base::MessageLoop* message_loop =      globals.threads[identifier] ? globals.threads[identifier]->message_loop()                                  : NULL;  if (message_loop) {    if (nestable) {      message_loop->task_runner()->PostDelayedTask(from_here, task, delay);    } else {      message_loop->task_runner()->PostNonNestableDelayedTask(from_here, task,                                                              delay);    }  }  if (!target_thread_outlives_current)    globals.lock.Release();  return !!message_loop;}

该函数通过ID标示获取获取线程的消息循环,然后通过线程的消息循环投递给具体的线程具体的消息循环任务。

0 0
原创粉丝点击