当前位置:网站首页>V79.01 Hongmeng kernel source code analysis (user mode locking) | how to use the fast lock futex (Part 1) | hundreds of blogs analyze the openharmony source code
V79.01 Hongmeng kernel source code analysis (user mode locking) | how to use the fast lock futex (Part 1) | hundreds of blogs analyze the openharmony source code
2022-07-01 08:36:00 【Hongmeng kernel source code analysis】
Analysis of 100 blogs | This article is :( User state lock ) | How to use quick lock Futex( On )
Process communication related articles are :
- v26.08 Hongmeng kernel source code analysis ( spinlocks ) | Be a good comrade of chastity archway
- v27.05 Hongmeng kernel source code analysis ( The mutex ) | It's the same lock, but it's fuller
- v28.04 Hongmeng kernel source code analysis ( Process communication ) | Nine ways of interprocess communication
- v29.05 Hongmeng kernel source code analysis ( Semaphore ) | Who is solving the synchronization between tasks
- v30.07 Hongmeng kernel source code analysis ( Event control ) | How to synchronize many to many tasks
- v33.03 Hongmeng kernel source code analysis ( Message queue ) | How to transfer big data asynchronously between processes
- v76.01 Hongmeng kernel source code analysis ( Shared memory ) | The fastest way to communicate between processes
- v77.02 Hongmeng kernel source code analysis ( Message encapsulation ) | analyse LiteIpc( On ) Process communication content
- v78.01 Hongmeng kernel source code analysis ( Message mapping ) | analyse LiteIpc( Next ) Process communication mechanism
- v79.01 Hongmeng kernel source code analysis ( User state lock ) | How to use quick lock Futex( On )
Quick lock Chapter 3
Hongmeng kernel realizes Futex
, This series will use three articles to introduce Quicklock , There are two main reasons :
- Introduction Online
Futex
There are very few articles , A comprehensive and in-depth introduction to the kernel is even less , So let's sort it out and dig it out . - It involves the cooperation between user mode and kernel mode , Interaction means the use of user state ( A piece of ) But also to clarify the implementation of kernel state ( Two articles ). This is the first one , How to use in user mode
Futex
, And with the help of ademo
Explain the whole process .
Basic concepts
Futex
(Fast userspace mutex
, User mode fast mutex ), Series abbreviation Quick lock , It's a Linux Implement locking and build high-level Abstract locks such as semaphores and POSIX The basic tool of mutual exclusion , It first appeared in linux
Kernel developed 2.5.7 edition ; Its semantic meaning is 2.5.40 Fixed , And then in 2.6.x Series stable kernel appears , It is a system call capability provided by the kernel . Generally, as a basic component, it is combined with the relevant lock logic of user state to form user state lock , It is a kind of lock in which user state and kernel state work together , Its user state part is responsible for locking logic , The kernel state part is responsible for lock scheduling .
When a user thread requests a lock , First, judge and maintain the lock status in user status , If there is no lock competition at this time , Then lock it directly in the user status and return ; conversely , You need to suspend the thread , adopt Futex
The system call requests kernel intervention to suspend the thread , And maintain the blocking queue .
When the user thread releases the lock , First, judge and maintain the lock status in user status , If no other thread is blocked by the lock at this time , Then unlock directly in user status and return to ; conversely , You need to wake up the blocked thread , adopt Futex
The system call requests the kernel to intervene to wake up the thread in the blocking queue .
Meaning of being
The mutex (
mutex
) You must enter the kernel state to know whether the lock can be used or not , If no one disputes with you, take the lock and return to the user state , If someone argues, you have to wait ( Include Finite time waiting and infinite waiting , All need to make wayCPU
Executive power ) Or abandon this application and return to the user status to continue execution . Then why The mutex Be sure to fall into kernel state check ? The mutex (mutex
) The essence is to compete for a global variable in kernel space (LosMux
Structure ). Applications also have global variables , But its scope is only valid in its own user space , It belongs to internal resources , Competition is also solved internally by the application itself . And the resource competition between applications ( Kernel resources ) You need a kernel program to solve , There is only one kernel space , Of course, the global variables of the kernel should be managed by the kernel . If an application wants to use kernel resources, it must fall into kernel state through system call , Take over the kernelCPU
, The essence of takeover is to change the program status register ,CPU
Switch from user mode stack to kernel mode stack and run , After the execution is completed, you have to switch back to the user status stack to continue the execution , In this way, there is a loss of system performance in the context switching between stacks . If you don't understand, please go to the series ( Mutex ) Look over .Quick lock The solution is whether you can know whether the lock is available in the user state , Because competition doesn't happen all the time , When you go to the kernel state, in fact, no one will argue for you , Running back and forth in vain is a waste of performance . That's the question , How to know whether the lock is available in user mode ? Because you can't access the global variables of the kernel without falling into the kernel state . And the variables in their own private space are invalid for other processes and cannot be used . The deeper you study the kernel, the more you feel , The implementation of the kernel can be derived mathematically , Very interesting . Mathematics is actually based on several common sense axioms to deduce the whole mathematical system , Because you can't be self consistent without this logic . If you have a certain understanding of the kernel , Naturally, it can be deduced here with the help of Shared memory To achieve !
Using process
Look at linux futex official demo
Specify how to use in user mode Futex
The whole process , Not much code , But there are many knowledge points related to the kernel , Through it, we can test the solid level of basic skills of the kernel .
//futex_demo.c#define _GNU_SOURCE#include <stdio.h>#include <errno.h>#include <stdatomic.h>#include <stdint.h>#include <stdlib.h>#include <unistd.h>#include <sys/wait.h>#include <sys/mman.h>#include <sys/syscall.h>#include <linux/futex.h>#include <sys/time.h>#define errExit(msg) do { perror(msg); exit(EXIT_FAILURE); \ } while (0)static uint32_t *futex1, *futex2, *iaddr;/// Fast system call static int futex(uint32_t *uaddr, int futex_op, uint32_t val, const struct timespec *timeout, uint32_t *uaddr2, uint32_t val3){ return syscall(SYS_futex, uaddr, futex_op, val, timeout, uaddr2, val3);}/// Apply for quick lock static void fwait(uint32_t *futexp){ long s; while (1) { const uint32_t one = 1; if (atomic_compare_exchange_strong(futexp, &one, 0)) break; // Apply for quick lock successfully // Failed to apply for quick lock , Need to wait s = futex(futexp, FUTEX_WAIT, 0, NULL, NULL, 0); if (s == -1 && errno != EAGAIN) errExit("futex-FUTEX_WAIT"); }}/// Release the quick lock static void fpost(uint32_t *futexp){ long s; const uint32_t zero = 0; if (atomic_compare_exchange_strong(futexp, &zero, 1)) {// Release the quick lock successfully s = futex(futexp, FUTEX_WAKE, 1, NULL, NULL, 0);// Wake up and wait for the lock process / Threads if (s == -1) errExit("futex-FUTEX_WAKE"); }}/// The process of father son competition is fast int main(int argc, char *argv[]){ pid_t childPid; int nloops; setbuf(stdout, NULL); nloops = (argc > 1) ? atoi(argv[1]) : 3; iaddr = mmap(NULL, sizeof(*iaddr) * 2, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_SHARED, -1, 0);// Create read-write anonymous shared memory if (iaddr == MAP_FAILED) errExit("mmap"); futex1 = &iaddr[0]; // Bind lock an address futex2 = &iaddr[1]; // Bind lock 2 address *futex1 = 0; // Lock 1 cannot be applied *futex2 = 1; // Lock two can apply for childPid = fork(); if (childPid == -1) errExit("fork"); if (childPid == 0) {// Subprocess return for (int j = 0; j < nloops; j++) { fwait(futex1);// Apply for a lock printf(" Subprocesses (%jd) %d\n", (intmax_t) getpid(), j); fpost(futex2);// Release lock 2 } exit(EXIT_SUCCESS); } // The parent process returns execution for (int j = 0; j < nloops; j++) { fwait(futex2);// Apply for lock two printf(" The parent process (%jd) %d\n", (intmax_t) getpid(), j); fpost(futex1);// Release the lock } wait(NULL); exit(EXIT_SUCCESS);}
Code in wsl2
The results of compiling and running on are as follows :
[email protected]:/home/turing# gcc ./futex_demo.c -o [email protected]:/home/turing# ./futex_demo The parent process (283) 0 Subprocesses (284) 0 The parent process (283) 1 Subprocesses (284) 1 The parent process (283) 2 Subprocesses (284) 2
Reading
- By system call
mmap
Create a readable and writable shared memoryiaddr[2]
integer array , Complete twofutex
Lock initialization . The kernel allocates a shared linear area in memory (MAP_ANONYMOUS
|MAP_SHARED
), The linear area is readable and writable (PROT_READ
|PROT_WRITE
)
suchfutex1 = &iaddr[0]; // Bind lock an address futex2 = &iaddr[1]; // Bind lock 2 address *futex1 = 0; // Lock 1 cannot be applied *futex2 = 1; // Lock two can apply for
futex1
andfutex2
Have initial values and are all shared variables , Want to learn moremmap
Viewable series of Kernel Implementation ( Linear section ) and ( Shared memory ) In detail . childPid = fork();
Created a subprocess ,fork The mapping of the linear area of the parent process will be copied to the child process , The result is that the parent process shares the linear region to the child process, which is also the shared linear region , The mapping is the same physical address . Yesfork
Please go to the unfamiliar , Series (fork piece )| One call , Two returns Specifically, it .fwait
( To apply for the lock ) Andfpost
( Release the lock ) Pairs appear , Look at the lock application process alone
The infinite loop break On the condition that/// Apply for quick lock static void fwait(uint32_t *futexp){ long s; while (1) { const uint32_t one = 1; if (atomic_compare_exchange_strong(futexp, &one, 0)) break; // Apply for quick lock successfully // Failed to apply for quick lock , Need to wait s = futex(futexp, FUTEX_WAIT, 0, NULL, NULL, 0); if (s == -1 && errno != EAGAIN) errExit("futex-FUTEX_WAIT"); }}
atomic_compare_exchange_strong
It's true , This is an atomic comparison operation , It must be used here , As for why, please go to the series ( Atomic operation )| Who's protecting integrity , Note that it is understandingFutex
The key , It means
The value pointed to obj Atomic comparison with the value pointed toIn the header file <stdatomic.h> In the definition of _Bool atomic_compare_exchange_strong(volatile A * obj,C * expected,C desired);
expected
, If equal , Replace the former with the formerdesired
( Perform read - modify - Write operation ). otherwise , Load the... That the actual value points toobj
Get into*expected
( Carry out load operation ). What do you mean ? A straightforward explanation :- If
futexp == 1
beatomic_compare_exchange_strong
Return to true , At the same timefutexp
The value of the into0
,1 Means you can hold the lock , Once held, it becomes 0, Others won't get it . So here is very second . And this happens in user mode . - If
futexp == 0
atomic_compare_exchange_strong
Return to leave , Didn't get the lock , You need to fall into the kernel state to suspend the task and wait for the release of the lock
The last parameter is zerofutex(futexp, FUTEX_WAIT, 0, NULL, NULL, 0) // Execute a system call waiting for a lock
0
It means not staying in the kernel state and directly returning to the user state , The following will be explained in detail in the kernel state section .- If
childPid == 0
Is the return of the child process . Keep applyingfutex1
Releasefutex2
if (childPid == 0) {// Subprocess return for (int j = 0; j < nloops; j++) { fwait(futex1); printf(" Subprocesses (%jd) %d\n", (intmax_t) getpid(), j); fpost(futex2); } exit(EXIT_SUCCESS);}
- The return of the last parent process , Keep applying
futex2
Releasefutex1
// The parent process returns execution for (int j = 0; j < nloops; j++) { fwait(futex2); printf(" The parent process (%jd) %d\n", (intmax_t) getpid(), j); fpost(futex1);}wait(NULL);exit(EXIT_SUCCESS);
- The initial value of the two locks is
*futex1 = 0; *futex2 = 1;
, The parent process is infwait(futex2)
So the parent processprintf
Will be executed first ,*futex2 = 0;
Lock two becomes not applicable , Release after printingfpost(futex1)
Make the result*futex1 = 1;
It means that the lock can be applied for , And the child process is waitingfwait(futex1)
, The result of alternating execution isThe parent process (283) 0 Subprocesses (284) 0 The parent process (283) 1 Subprocesses (284) 1 The parent process (283) 2 Subprocesses (284) 2
Baiwen said that the kernel | Grasp the main context
- Baiwen is equivalent to touching the muscle and organ system of the core , It makes people feel plump and three-dimensional , Because it starts directly from the annotation source code , In the process of annotation , Whenever you have something to learn, sort it out , Slowly formed the following articles . The content is based on the source code , Often take the life scene as an example, put as many kernel knowledge points as possible into a certain scene , With a sense of picture , Easy to understand and remember . It's important to say what others can understand ! A hundred blogs is by no means Baidu's dogmatic talk about a bunch of concepts that are being heckled , That's not interesting . I want to make the kernel more lifelike , I feel very kind .
- And the code needs to be constantly
debug
equally , There will be many mistakes and omissions in the content of the article , Please forgive me , But it will be fixed over and over again , Continuous updating ,v**.xx
Represents the article serial number and the number of modifications , Finely crafted , simply , Strive to create quality content . - Bai Wenzai < Hongmeng research station | Open source in China | Blog Garden | 51cto | csdn | You know | Nuggets > Website publishing , The official account replied Baiwen Easy to read .
Press function module :
- Ins and outs >> General catalogue | Scheduling story | Memory master slave | Source code comments | Source structure | Static site | Reference documents |
- Basic tools >> Double linked list | Bitmap management | Stack mode | Timer | Atomic manipulation | time management |
- Load run >> ELF Format | ELF analysis | Static links | relocation | Process image |
- Process management >> Process management | Process concept | Fork | Special process | Process recycling | Signal production | Signal consumption | Shell edit | Shell analysis |
- Compiling and constructing >> Compile environment | The build process | Environment script | Building tools | gn application | ninja ninja |
- Process communication >> spinlocks | The mutex | Process communication | Semaphore | Event control | Message queue | Shared memory | Message encapsulation | Message mapping | User state lock |
- memory management >> Memory allocation | memory management | Memory assembly | Memory mapping | Memory rules | Physical memory |
- task management >> Clock task | Task scheduling | task management | Scheduling queues | Scheduling mechanism | Thread concept | Concurrent parallel | CPU | system call | Task switching |
- file system >> Document concept | file system | The index node | Mount Directory | The root file system | VFS | File handle | Pipeline files |
- Hardware architecture >> Assembly basis | Assembly pass parameters | Working mode | register | Abnormal connection | Compilation summary | Interrupt switching | The concept of interruption | Interrupt management |
- Device drivers >> Character device | Console | Remote login |
Million note source code | Buckle details everywhere
The purpose of million Chinese characters annotation core is to see its capillaries , Cell structure , It's like looking at the core with a magnifying glass . The kernel is not mysterious , It's easy to be addicted to finding answers in the source code with questions , You will find that many articles interpret some problems incorrectly , Or it's hard to justify it without being profound , You will slowly form your own new interpretation , And the new interpretation will encounter new problems , And so on , Roll forward , Holding a magnifying glass, I don't want to let go at all .
< gitee | github | coding | codechina > Four big yards push | Synchronize the official source code , Reply in official account One million Easy to read .
Focus on not getting lost | Code is life
边栏推荐
猜你喜欢
MATLAB【函数和图像】
Practice and Thinking on the architecture of a set of 100000 TPS im integrated message system
What is the material of 16MnDR, the minimum service temperature of 16MnDR, and the chemical composition of 16MnDR
Matlab [function derivation]
你了解数据是如何存储的吗?(C整型和浮点型两类)
电脑小技巧
factory type_id::create过程解析
为什么LTD独立站就是Web3.0网站!
Audio audiorecord create (I)
Comprehensive experiment Li
随机推荐
MATLAB小技巧(23)矩阵分析--模拟退火
Use threejs simple Web3D effect
Leetcode T39: 组合总和
一文纵览主流 NFT 市场平台版税、服务费设计
截图小妙招
C语言指针的进阶(下)
factory type_ Id:: create process resolution
爬虫知识点总结
《微机原理》-绪论
Embedded-c language-10-enumeration / (function) pointer (function) / multi-level pointer /malloc dynamic allocation / file operation
TypeError: __init__() got an unexpected keyword argument ‘autocompletion‘
【面试必刷101】链表
《微机原理》——微处理器内部及外部结构
[untitled]
《单片机原理及应用》-片外拓展
Provincial election + noi Part VII computational geometry
2022.2.15
2022 Chinese cook (technician) simulation test and Chinese cook (technician) practice test video
Matlab tips (23) matrix analysis -- simulated annealing
Utiliser Beef pour détourner le navigateur utilisateur