chromium - FROM_HERE

前言

在看chromium的任务处理部分.

chromium中的任务都是异步处理的(防止阻塞UI).

发起点投递任务到任务队列中,另外一个处理线程(用DoLoop设计模式)从任务队列中弹出任务,进行处理。

这时,如果在异步弹出任务时,知道任务是在哪个点投递到任务队列的,这对调试很有用。在vs2017中就可以直接搜索到代码发起点,在任务发起点下断点,这样就能将任务的发起和处理联系在一起了。

看到投递任务时的FROM_HERE宏,这个宏的用法还挺高级,比一般工程的宏(文件名,函数名,当前行)写的多了一个返回地址(实际上起的作用是指示调用点)的记录.

由于FROM_HERE中调用_ReturnAddress()时,是在子函数中完成的,宏记录的地址,实际上就是调用点的地址。这挺巧的。

实验

调用点加入FROM_HERE

void ServiceThread::Init() {
  // In unit tests we sometimes do not have a fully functional TaskScheduler
  // environment, do not perform the heartbeat report in that case since it
  // relies on such an environment.
  if (task_tracker_ && TaskScheduler::GetInstance()) {
    heartbeat_latency_timer_.Start(
        FROM_HERE, TimeDelta::FromSeconds(5),
        BindRepeating(&ServiceThread::PerformHeartbeatLatencyReport,
                      Unretained(this)));
  }
}

// The macros defined here will expand to the current function.
#if BUILDFLAG(ENABLE_LOCATION_SOURCE)

// Full source information should be included.
#define FROM_HERE FROM_HERE_WITH_EXPLICIT_FUNCTION(__func__)
#define FROM_HERE_WITH_EXPLICIT_FUNCTION(function_name) \
  ::base::Location::CreateFromHere(function_name, __FILE__, __LINE__)

#else

// static
NOINLINE Location Location::CreateFromHere(const char* function_name,
                                           const char* file_name,
                                           int line_number) {
  return Location(function_name, file_name, line_number, RETURN_ADDRESS());
}

#if defined(COMPILER_MSVC)
#define RETURN_ADDRESS() _ReturnAddress()
#elif defined(COMPILER_GCC) && !defined(OS_NACL)

看到_ReturnAddress()时,因为没用过,感到挺稀罕的。想看看_ReturnAddress的效果。

实验 - _ReturnAddress

// @file main.cpp
// @brief test _ReturnAddress
// @note

// C:\Program Files (x86)\Microsoft Visual Studio\2017\Enterprise\VC\Tools\MSVC\14.15.26726\include\intrin.h
#include <intrin.h>

#include <iostream>

void test();

int main()
{
	printf("test() addr = 0x%p\n", &test);
	test(); // 在test中得到的p_addr为下面的test()调用的地址
	test(); // 在test中得到的p_addr为下面的test()调用的地址
	test(); // 在test中得到的p_addr为下面的return EXIT_SUCCESS调用的地址

	return EXIT_SUCCESS;
}

/** run result
p_addr = 0x0108196D

p_addr = 0x0023196D
*/

void test()
{
	void* p_addr = _ReturnAddress();

	// _ReturnAddress() 的汇编实现,很直白, 将函数栈上的返回地址直接给了变量
	// 009917F8  mov         eax, dword ptr[ebp + 4]
	// 009917FB  mov         dword ptr[p_addr], eax

	// intrin.h 中有很多操作寄存器的函数,相当于用高级语言写汇编程序了

	printf("p_addr1 = 0x%p\n", p_addr);

	p_addr = _ReturnAddress();
	printf("p_addr2 = 0x%p\n", p_addr);
}

通过实验可知,_ReturnAddress()实际上是MS编译器对汇编代码的简单封装, 等于是用C语言可以直接写汇编代码了.

在intrin.h中,还有很多可以操作寄存器的函数。以后有空,可以再研究一下其他API的用法。

猜你喜欢

转载自blog.csdn.net/LostSpeed/article/details/85329348