BrowserProcessSubThread

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 Site
00 00000000`0684f648 000007fe`fdb910dc ntdll!NtWaitForSingleObject+0xa
01 00000000`0684f650 000007fe`ef200e54 KERNELBASE!WaitForSingleObjectEx+0x79
02 (Inline Function) --------`-------- chrome_7feef160000!base::WaitableEvent::TimedWait+0x95
03 00000000`0684f6f0 000007fe`ef1edd83 chrome_7feef160000!base::MessagePumpDefault::Run+0x1c4
04 (Inline Function) --------`-------- chrome_7feef160000!base::MessageLoop::RunHandler+0x15
05 00000000`0684f950 000007fe`ef1c4381 chrome_7feef160000!base::RunLoop::Run+0x83
06 (Inline Function) --------`-------- chrome_7feef160000!base::MessageLoop::Run+0x35
07 00000000`0684f9a0 000007fe`f01d8076 chrome_7feef160000!base::Thread::Run+0x41
08 00000000`0684fa00 000007fe`f01d8d3e chrome_7feef160000!content::BrowserThreadImpl::DBThreadRun+0x36
09 00000000`0684fb50 000007fe`ef1c46d8 chrome_7feef160000!content::BrowserThreadImpl::Run+0xca
0a 00000000`0684fb80 000007fe`ef1d7e9d chrome_7feef160000!base::Thread::ThreadMain+0x338
0b 00000000`0684fbf0 00000000`7714652d chrome_7feef160000!base::`anonymous namespace'::ThreadFunc+0x15d
0c 00000000`0684fc60 00000000`7762c521 kernel32!BaseThreadInitThunk+0xd
0d 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(
    .......

    // static
bool 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
// static
bool 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标示获取获取线程的消息循环,然后通过线程的消息循环投递给具体的线程具体的消息循环任务。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值