前言
在看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的用法。