当前位置:网站首页>Source code analysis of Tencent libco collaboration open source library (III) -- Exploring collaboration switching process assembly register saving and efficient collaboration environment
Source code analysis of Tencent libco collaboration open source library (III) -- Exploring collaboration switching process assembly register saving and efficient collaboration environment
2022-06-10 19:40:00 【Love 6】
List of articles
- Full series summary blog links
- Foreword
- tencent Libco Collaborative open source library Source code analysis ( 3、 ... and )---- Explore the coordination process switching process Assembly register save Save the collaborative process environment efficiently
- Conclusion
Full series summary blog links
tencent Libco Collaborative open source library Source code analysis Full series summary blog
Foreword
For CO process switching This part I have done it quite thoroughly
For the later call blocking function Assist the process to achieve active scheduling and give up cpu This part I'll think it over later Save it for your next blog post This article mainly writes two functions co_resume and co_yield The principle of
tencent Libco Collaborative open source library Source code analysis ( 3、 ... and )---- Explore the coordination process switching process Assembly register save Save the collaborative process environment efficiently
1、 Explore co_resume The principle of startup coprocessor function
The number of lines of code is very short But it needs to be tapped
The first line gets the... Of the current thread env Environmental Science This is the same for all coroutines in each thread It was introduced before Not much
The second line Get the currently running stack Process management structure pointer For the first callco_resumeOf What we get at this time ismainPointer to function
The third line Is the first call to all coroutinesco_resumecStartIs zero If the previous collaboration has been started Then callco_resumeWords This statement segment will no longer enter
We can take a closer look at what is going on inside this function To look down
void co_resume( stCoRoutine_t *co )
{
stCoRoutineEnv_t *env = co->env;
stCoRoutine_t *lpCurrRoutine = env->pCallStack[ env->iCallStackSize - 1 ];
if( !co->cStart )
{
coctx_make( &co->ctx,(coctx_pfn_t)CoRoutineFunc,co,0 );
co->cStart = 1;
}
env->pCallStack[ env->iCallStackSize++ ] = co;
co_swap( lpCurrRoutine, co );
}
1、 hitting coctx_make function Tapping and unthreading
coctx_make We can look at the definition of this function
Here I choose
32Bit operating system The version of the function called because32I am familiar with And later for32 positionThe flow of function calls under the operating system They are also familiar with each other and64 positionIt's relatively different But the principle is the same Just the calling process is different So, by default32 positionThe function version under
We analyze it line by line In this function, we also give Definitions of related structures and functions Easy to read
first line Set up esp Location If you are not familiar with the underlying knowledge or do not know the assembly language For registers in function calls If you don't understand the function I suggest we make up the foundation again Let me explain here why we need to subtractsizeof(coctx_param_t)Here we are just making room for the following function parameters The specific function is given aboveCoRoutineFuncThis parameter makes room for And assign the parameter here
The second line Align stack space with memory location I thought about It should be the end of clearing 4 Address of bit
Lines three through seven Doing two things First of all For the following assembly functioncoctx_swapOfretfunction Arrange the returned function address The second thing Just forCoRoutineFuncparameter assignment
For function parameter passing I believe this diagram is the clearest parameter transfer flowchart I have ever seen Of course This is limited to 32 position 64 Bit is a little different But it doesn't make much difference I'm not sure So I won't say more 64 Yes.
Parameter passing is the later parameter The more advanced Push To stack Then finally push Function address
Here we useespAddressing In fact, it is generally not in the form ofespAddressing But ratherebpAddressing But it's almost the same When generating assembly code There will be a codemovl esp, ebptake esp The value of is assigned to ebp Fix the header of the current stack frame Then call parameters.
Above description It is also the assigned address to the following And the explanation of function address assignment If there is a certain compilation basis I believe think It's still easy to figure out why the assignment is like this

As for this part Let's talk about the last line Will esp Subtract two more from your address void* Well Here I also thought for a while It can be said that I have come up with a reason
As there is no coctx_swap Assembler function code It will be given later The normal situation should be after making room for parameters Right where you are Assignment function pointer ret that will do Why subtract two more void* Just assign values
In my submission This problem Maybe only I know more about assembly And it is really possible that only those who have a deep understanding of the operating system can understand
Is that we are c Language After calling assembly c Language Compile into assembly It should be first push After the parameter Again push Function return address But we are in the back coctx_swap in We have changed esp The address of But the operating system doesn't care As the assembly function is called The last sentence ret The end of Is it really over Certainly not. There will be another assembly line generated later It is to pass parameters before recycling And the stack space automatically allocated downward Now it needs to be recycled
But the operating system is not clear. We switched esp But there's no way He must perform a call to reclaim parameters Statements that occupy stack space So here we have subtracted two more down void* Back recycling It's actually recycled Our new one is malloc Own stack space
Maybe my thinking is wrong But I've been thinking for a long time. I can only think like this And I do feel like this
typedef void* (*coctx_pfn_t)( void* s, void* s2 );
struct coctx_param_t
{
const void *s1;
const void *s2;
};
struct coctx_t
{
#if defined(__i386__)
void *regs[ 8 ];
#else
void *regs[ 14 ];
#endif
size_t ss_size;
char *ss_sp;
};
static int CoRoutineFunc( stCoRoutine_t *co,void * )
{
if( co->pfn )
{
co->pfn( co->arg );
}
co->cEnd = 1;
stCoRoutineEnv_t *env = co->env;
co_yield_env( env );
return 0;
}
int coctx_make(coctx_t* ctx, coctx_pfn_t pfn, const void* s, const void* s1) {
// make room for coctx_param
char* sp = ctx->ss_sp + ctx->ss_size - sizeof(coctx_param_t);
sp = (char*)((unsigned long)sp & -16L);
coctx_param_t* param = (coctx_param_t*)sp;
void** ret_addr = (void**)(sp - sizeof(void*) * 2);
*ret_addr = (void*)pfn;
param->s1 = s;
param->s2 = s1;
memset(ctx->regs, 0, sizeof(ctx->regs));
ctx->regs[kESP] = (char*)(sp) - sizeof(void*) * 2;
return 0;
}
2、 follow up a victory with hot pursuit to co_swap Make a clean sweep of the process switching
It's over coctx_make Here we come co_resume The last line of code co_swap The core of this function is to call the assembly function coctx_swap Let's see
In fact, for the code here If the shared stack is not used The only thing to focus on is a line of code Other code is related to the shared stack Let's skip
Assembly code is called herecoctx_swapAfter this line of code runs The coordination process is switched When I come back next time It is necessary to waitco_yieldWill return to the next line of code So let's seecoctx_swapWell
void co_swap(stCoRoutine_t* curr, stCoRoutine_t* pending_co)
{
stCoRoutineEnv_t* env = co_get_curr_thread_env();
//get curr stack sp
char c;
curr->stack_sp= &c;
if (!pending_co->cIsShareStack)
{
env->pending_co = NULL;
env->occupy_co = NULL;
}
else
{
env->pending_co = pending_co;
//get last occupy co on the same stack mem
stCoRoutine_t* occupy_co = pending_co->stack_mem->occupy_co;
//set pending co to occupy thest stack mem;
pending_co->stack_mem->occupy_co = pending_co;
env->occupy_co = occupy_co;
if (occupy_co && occupy_co != pending_co)
{
save_stack_buffer(occupy_co);
}
}
//swap context
coctx_swap(&(curr->ctx),&(pending_co->ctx) );
//stack buffer may be overwrite, so get again;
stCoRoutineEnv_t* curr_env = co_get_curr_thread_env();
stCoRoutine_t* update_occupy_co = curr_env->occupy_co;
stCoRoutine_t* update_pending_co = curr_env->pending_co;
if (update_occupy_co && update_pending_co && update_occupy_co != update_pending_co)
{
//resume stack buffer
if (update_pending_co->save_buffer && update_pending_co->save_size > 0)
{
memcpy(update_pending_co->stack_sp, update_pending_co->save_buffer, update_pending_co->save_size);
}
}
}
coctx_swap.S
If you haven't learned assembly Here's the suggestion You can go directly to the upper right corner
Because it is Look at some C/C++ The underlying code If you don't know about assembly It has nothing to do with background development So I'd better take a few days to supplement the foundation and have a look
It has been written in great detail About C Language Function call process
So for the above statement coctx_swap(&(curr->ctx),&(pending_co->ctx)) We can easily know at present The pointer position of the target function we are about to turn to Is in coctx_t in esp Where it is stored
And for parameters &(curr->ctx) It should be in esp + 4 The location of &(pending_co->ctx) Is in esp + 8 The location of
With this pre knowledge We can do a lot with the following assembly code
The first paragraph
The first line assembles Put our current cooperation process coctx_t Value Put in eax in
Lines 2 through 8 assemble Is to put our current 8 All registers are stored in our structurestruct coctx_tin I gave it to you earlierstruct coctx_tThe definition of You can look for it
The second paragraph
The first line assembles Coordinate our goals coctx_t Value Put in eax in
Lines 2 through 8 assemble Put our structurestruct coctx_tin Preset 8 A register ( In fact, only esp There is a value ) Stored in the current register
The last line CalledretBecause of ourespIt has been switched to the presetespSo at this timeretThen he jumped to The pre-set covariance functionCoRoutineFunc
64 Bit assembly code is a little more complicated But the principle is similar Let's see 32 You can
Now let's go and have a lookCoRoutineFuncWhat are you doing
.globl coctx_swap
#if !defined( __APPLE__ )
.type coctx_swap, @function
#endif
coctx_swap:
#if defined(__i386__)
movl 4(%esp), %eax
movl %esp, 28(%eax)
movl %ebp, 24(%eax)
movl %esi, 20(%eax)
movl %edi, 16(%eax)
movl %edx, 12(%eax)
movl %ecx, 8(%eax)
movl %ebx, 4(%eax)
movl 8(%esp), %eax
movl 4(%eax), %ebx
movl 8(%eax), %ecx
movl 12(%eax), %edx
movl 16(%eax), %edi
movl 20(%eax), %esi
movl 24(%eax), %ebp
movl 28(%eax), %esp
ret
3、 ordinary CoRoutineFunc end co_resume
Remember before for
espTeng's parameter space see( stCoRoutine_t *co,void * )And that's where it comes in Here we get the parameters It was beforecoctx_makeParameters stored in Why is it stored there Think about function parameter calls
thenco->pfn(co->arg)Is the function call of the initial setting of the coroutine In our sample code yesreadwrite_routine
There is nothing else left
}
static int CoRoutineFunc( stCoRoutine_t *co,void * )
{
if( co->pfn )
{
co->pfn( co->arg );
}
co->cEnd = 1;
stCoRoutineEnv_t *env = co->env;
co_yield_env( env );
return 0;
}
2、 Look again. co_yield_ct
In fact, it feels a little cut here Because the active release process Switch coroutines
Not just active calls co_yield_ct() And call some blocking functions ( Of course, it's just a simulated blocking function In fact, it calls the function version implemented by itself ) Has reached the awaited Will take the initiative yield
About calling blocking functions why yield Let's save it for the last article
Here's another look You can choose to give up CPU Function of co_yield_ct How did it happen
It is relatively easy and simple here Let's save the complicated ones for the last one
1、co_yield Series of functions
Here's a simple look co_yield Definition of function
It is found that these two functions are just wrapped in a layer of outer packaging
The essence is called co_yield_env Let's go to this function again
void co_yield_ct()
{
co_yield_env( co_get_curr_thread_env() );
}
void co_yield( stCoRoutine_t *co )
{
co_yield_env( co->env );
}
2、 Light hearted co_yield_env function
It is as expected Sure enough, it is still a very relaxing function
Only four lines It is the same as what we said before
Get the previous collaboration structure call co_swap Switch to the original collaboration Continue the previous cooperation process
It's that simple ~
void co_yield_env( stCoRoutineEnv_t *env )
{
stCoRoutine_t *last = env->pCallStack[ env->iCallStackSize - 2 ];
stCoRoutine_t *curr = env->pCallStack[ env->iCallStackSize - 1 ];
env->iCallStackSize--;
co_swap( curr, last);
}
Conclusion
Write another one later About calling blocking functions How to actively switch processes
To study See you next ~ ヾ( ̄▽ ̄)Bye~Bye~
边栏推荐
- c(指针-02)
- Implementation analysis of single image haze removal using dark channel prior
- 超级简单的课程设计ssm学生管理系统(含源码简单添加、删除、修改、查询操作)
- 【C语言】这些经典题型大家都掌握了吗?一文学会这些题
- Design and development of hospital reservation registration platform based on JSP Zip (thesis + project source code)
- SPSS introductory notes
- Writing technical articles is a fortune for the future
- This article introduces you to j.u.c's futuretask, fork/join framework and BlockingQueue
- 通过举栗子的方式来讲解面试题(可面试,可复习,可学习)
- Ruixin micro rk1126 platform platform porting libevent cross compiling libevent
猜你喜欢

What are the current mainstream all-optical technology solutions- Part II

Super simple course design SSM student management system (including simple addition, deletion, modification and query of source code)

Basic improvement - tree DP supplement

一文带你了解J.U.C的FutureTask、Fork/Join框架和BlockingQueue

APICloud可视化开发新手图文教程
![[C language] accidentally write a bug? Mortals teach you how to write good code [explain debugging skills in vs]](/img/34/6f254e027e5941bb2c3462b665c3ba.png)
[C language] accidentally write a bug? Mortals teach you how to write good code [explain debugging skills in vs]
![MySQL advanced Chapter 1 (installing MySQL under Linux) [i]](/img/f9/60998504e20561886b5f62eb642488.png)
MySQL advanced Chapter 1 (installing MySQL under Linux) [i]

Analysis of optical storage direct flexible power distribution system

Computer: successfully teach you how to use one trick to retrieve the previous password (the password once saved but currently displayed as ******)

Lingo12 software download and lingo language introduction resources
随机推荐
2022.05.29(LC_6078_重排字符形成目标字符串)
Design and implementation of SSM based traffic metering cloud system Rar (thesis + project source code)
Vs solution to garbled Chinese characters read from txt files (super simple)
[advanced C language] data storage [Part 2] [ten thousand words summary]
Google Earth engine (GEE) -- Copernicus atmosphere monitoring (CAMs) global aerosol AOI near real-time observation data set
【 Web 】 page d'accueil personnelle 】 Programme d'études 】 albums de photos 】 babillard d'information 】
Morris traversal of binary tree
一文带你了解J.U.C的FutureTask、Fork/Join框架和BlockingQueue
Musk says he doesn't like being a CEO, but rather wants to do technology and design; Wu Enda's "machine learning" course is about to close registration | geek headlines
Apicloud visual development - one click generation of professional source code
个人如何投资理财比较安全?
MySQL advanced Chapter 1 (installing MySQL under Linux) [i]
【C语言进阶】指针的进阶【中篇】
Jsp基于ssm项目实验室管理系统设计与现实.doc
SAR图像聚焦质量评价插件
100003 words, take you to decrypt the system architecture under the double 11 and 618 e-commerce promotion scenarios
What are the current mainstream all-optical technology solutions- Part II
Computer: successfully teach you how to use one trick to retrieve the previous password (the password once saved but currently displayed as ******)
[advanced C language] data storage [part I] [ten thousand words summary]
多通道信号数据压缩存储