Home  >  Article  >  System Tutorial  >  In-depth analysis of the Linux kernel source code and exploration of the essence of the operating system

In-depth analysis of the Linux kernel source code and exploration of the essence of the operating system

WBOY
WBOYOriginal
2024-08-08 09:33:081042browse

深入解析 Linux 内核源码,探索操作系统本质

1. My opinion on the kernel source code

The sheer size of the Linux kernel code makes many people "daunted". It is precisely because of this that people's understanding of Linux is only at a general level. If you want to analyze Linux and delve into the nature of the operating system, reading the kernel source code is the most effective way. We all know that becoming an excellent programmer Linux kernel source code analysis requires a lot of practice and code compilation. Programming is still important, and often people who only program can easily limit themselves to their own areas of knowledge. If we want to expand the breadth of our knowledge, we need to be more exposed to code written by others, especially code written by people who are more advanced than us. Through these ways, we can break out of the confinement of our own knowledge circle, step into the knowledge circle of others, and learn more about information that we usually find difficult to understand in the short term. The Linux kernel is carefully maintained by countless "masters" in the open source community. Those people can be called top code experts. By reading the Linux kernel code, we learn not only kernel-related knowledge, but in my opinion, what is more valuable is learning and feeling their programming methods and understanding of computers.

I also came into contact with the analysis of Linux kernel source code through a project. I have benefited a lot from the analysis of source code. Not only did I acquire relevant kernel knowledge, it also changed my past understanding of kernel code:

1. The analysis of kernel source code is not "out of reach". The difficulty of kernel source code analysis does not lie in the source code itself, but in how to use more appropriate methods and methods to analyze the code. The complexity of the kernel means that we cannot analyze it step by step starting from the main function like analyzing a normal demo program. We need a way to intervene from the middle to "break through" the kernel source code one by one. These "on demand" formats allow us to grasp the main thread of the source code instead of getting too bogged down in the specific details.

2. The design of the core is beautiful. The special status of the kernel determines that the execution efficiency of the kernel must be high enough to respond to the real-time requirements of current computer applications. Therefore, the Linux kernel uses a hybrid programming of C language and assembly. And we all know that software execution efficiency and software maintainability run counter to each other in many cases. How to improve the maintainability of the kernel while ensuring the efficiency of the kernel depends on these "beautiful" designs in the kernel.

3. Amazing programming method. In the field of general application software design, the status of coding may not be overemphasized, because developers pay more attention to the good design of software, and coding is just a matter of implementation means-just like using an ax to chop firewood, without too much thinking. And this is not established in the kernel. Good coding design not only improves maintainability, but also improves code performance.

Everyone’s understanding of the kernel will be different. As our understanding of the kernel continues to deepen, we will have more thoughts and feelings about its design and implementation. Therefore, this article hopes to guide more people who are wandering outside the Linux kernel room into the world of Linux to personally experience the magic and greatness of the kernel. And I am not an expert in kernel source code. I just hope to share my own experience and insights in analyzing source code and provide reference and help to those who need it. To put it "high-sounding", it can be regarded as for the computer industry. Especially in the operating system kernel to contribute their own modest efforts. Without further ado (it’s already too long-winded, embarrassing~), let me share my own Linux kernel source code analysis method.

2. Is it difficult to source the kernel source code?

Essentially, analyzing Linux kernel code is no different from looking at other people's code, because the code in front of you is usually not the code you wrote yourself. Let's take a simple example first. A stranger gives you a program at random and asks you to explain the functional design of the program after reading the source code. I think many people who think that their programming skills are okay must think that this is nothing, as long as I patiently read his code from beginning to end, and I would definitely find the answer, but this is indeed the case. So now let's change the assumption, if this person is Linus, and what he gives you is the code of a module of the Linux kernel, do you think it is still so easy? Many people may hesitate. Why do we feel so different about the code given to you by the same stranger (not counting if Linus knows you, haha~)? I think there are the following reasons:

1. The Linux kernel code is somewhat mysterious to the "outside world", but it is very large, and it may be difficult to get started when it is placed in front of you. For example, it may start from a very small reason-the main function cannot be found. For a simple demo program, we can analyze the meaning of the code from beginning to end, and the method of analyzing the kernel code is completely ineffective, because no one can read the Linux code from beginning to end (because it is really not necessary, and when used, Just look at it).

2. Many people have also come into contact with the code of small software, but most of them are application projects. The form and meaning of the code are related to the business logic they often come into contact with. The kernel code is different. Most of the information it processes is closely related to the bottom layer of the computer. For example, the lack of relevant knowledge about operating systems, compilers, assembly, architecture, etc. will also make reading kernel code difficult.

3. The way to analyze the kernel code is not reasonable enough. Faced with a large amount of complex kernel code, if you don't start with Linux Mint from a global perspective, it is easy to get stuck in the quagmire of code details. After all, the kernel code is huge, and it also has its design principles and architecture, otherwise maintaining it would be a nightmare for anyone! If we clarify the overall design idea of ​​the code module and then analyze the implementation of the code, it may be easy and happy to analyze the source code.

linux内核源码剖析_linux内核源码是什么语言_linux内核源码分析

This is my personal understanding of those issues. If you have never been exposed to small software projects, analyzing Linux kernel code may be a good opportunity to accumulate experience in small projects (indeed, Linux code is the largest project I have been exposed to so far!). If you don’t understand the underlying aspects of computers thoroughly enough, we can choose to accumulate underlying knowledge by analyzing and learning at the same time. The progress of analyzing the code may be a little slow at first, but as knowledge continues to accumulate, our understanding of the "business logic" of the Linux kernel will gradually become clearer. The last point is how to master the source code of analysis from a global perspective. This is also the experience I want to share with you.

3. Kernel source code analysis method

Step one: data collection

From the perspective of people understanding new things, before exploring the essence of things, there must be a process of understanding new things. This process allows us to form a preliminary concept of new things. For example, if we want to learn guitar, we need to first understand that playing guitar requires us to learn basic sight-singing, simplified notation, staff and other basic knowledge, and then learn the methods and fingerings of erhu playing, and finally start practicing guitar.

The same is true for analyzing kernel code. First, we need to locate the content involved in the code to be analyzed. Is it the code for process synchronization and scheduling, the code for video memory management, the code for device management, the code for system startup, etc. The complexity of the kernel determines that we cannot analyze all the kernel code at once, so we need to give ourselves a reasonable division of labor. As algorithm design tells us, to solve a big problem, we must first solve the sub-problems it involves.

After locating the code range to be analyzed, we can use all the resources at hand to understand the overall structure and general functions of this part of the code as comprehensively as possible.

源码

All the resources mentioned here refer to Baidu, Google small online search engine, operating system principle textbooks and professional books, or experience and information provided by others, or even documents, comments and source code provided by Linux source code The name of the identifier (don't underestimate the naming of identifiers in the code, sometimes they can provide key information). In fact, all the resources here refer to all the available resources you can think of. In fact, it is unlikely that we can obtain all the information we want through these methods of information collection. We just want to be as comprehensive as possible. Because the more comprehensive the information is collected, the more information can be used in the process of analyzing the code, and the difficulty of the analysis process will be smaller.

Here is a simple counterexample. Suppose we want to analyze the code implemented by Linux's frequency conversion mechanism. So far we only know this term. From the literal meaning, we can roughly infer that it should be related to the frequency adjustment of the CPU. Through information collection, we should be able to obtain the following relevant information:

1. CPUFreq mechanism.

2. performance, powersave, userspace, ondemand, conservative frequency regulation strategies.

3. /driver/cpufreq/.

linux内核源码是什么语言_linux内核源码剖析_linux内核源码分析

4. /documention/cpufreq.

5. Pstate and Cstate.

……

If you can collect this kind of information when analyzing the Linux kernel code, you should be said to be very "lucky". Although the information about the Linux kernel is indeed not as rich as .NET and JQuery, compared with more than ten years ago, when there were no powerful search engines and no relevant research materials, it should be called a "big harvest" era! Through a simple "search" (which may take one to seven days), we even found the source code file directory where this part of the code is located. I have to say that this kind of information is simply "priceless"!

Step 2: Source code location

From the data collection, we were "lucky" to find the source code directory related to the source code. And this does not mean that we are actually analyzing the source code in this directory. Sometimes the directories we find may be scattered, and sometimes the directories we find contain a lot of code related to specific machines, and we are more concerned about the main mechanism of the code to be analyzed rather than the specialized code related to the machine ( This will help us understand the nature of the kernel more). To this end, we need to carefully select the information involving code files in the information. In fact, this step is unlikely to be completed at once, and no one can guarantee that all source code files to be analyzed can be selected at one time and none of them will be missed. And we don’t need to be afraid. As long as we can grasp the core source files related to most modules, we can naturally find them all through detailed analysis of the code later.

上記の例に戻り、/documention/cpufreq にあるドキュメントを注意深く読みます。現在の Linux ソース コードでは、モジュール関連のドキュメントがソース コード ディレクトリのドキュメント フォルダーに保存されます。分析対象のモジュールにドキュメントがない場合、これにより、主要なソース コード ファイルを見つける難しさがいくらか軽減され、問題が発生することはありません。解析したいソースコードが見つからない。ドキュメントを読むことで、少なくともソース ファイル /driver/cpufreq/cpufreq.c に注目することができます。このソース ファイルのドキュメントと、以前に収集した周波数変調戦略を組み合わせることで、5 つのソース ファイル cpufreq_performance.c、cpufreq_powersave.c、cpufreq_userspace.c、cpufreq_ondemand、および cpufreq_conservative.c に簡単に注目できます。関係する書類はすべて見つかったでしょうか?恐れることなく、それらから分析を開始してください。遅かれ早かれ、他のソース ファイルが見つかるでしょう。 Windows で SourceInsight を使用してカーネル ソース コードを読み取る場合、コード分析と組み合わせた関数呼び出しやシンボル参照の検索などの機能を通じて、他のファイル freq_table.c、cpufreq_stats.c、および /include/linux/cpufreq を簡単に見つけることができます。 h.

検索された情報の流れの方向に従って、分析が必要なソースコードファイルを完全に見つけることができます。すべてのソース コード ファイルを見つける必要はなく、作業の一部をコードの分析プロセスに延期できるため、ソース コードを見つける手順はそれほど重要ではありません。ソース コード ファイルの一部を見つけることも、ソース コードを分析するための基礎となります。

ステップ 3: 簡単なコメント

見つかったソース コード ファイルで、各変数、マクロ、関数、構造、その他のコード要素の一般的な意味と機能を分析します。これを単純なコメントと呼ぶのは、この部分のコメント作業が非常に単純であるという意味ではなく、この部分のコメントは、大まかに意味を説明するものであれば、あまり詳しく説明する必要はないという意味です。関連するコード要素。それどころか、ここでの作業は、分析プロセス全体の中で最も難しいステップであることは言うまでもありません。カーネル コードを深く掘り下げるのは初めてなので、特に初めてカーネル ソース コードを分析する人にとっては、多くのなじみのない GNU C 文パターンと圧倒的なマクロ定義に非常にがっかりするでしょう。この時点で、落ち着いてそれぞれの重要な困難を理解していれば、将来同じような困難に遭遇したときに退却を余儀なくされることはありません。さらに、カーネルに関連する他の知識も木のように拡大し続けます。

たとえば、「DEFINE_PER_CPU」マクロの使用は、cpufreq.c ファイルの先頭に表示されます。この情報を参照することで、このマクロの意味と機能を基本的に理解できます。ここで使用する方法は、以前にデータを収集するために使用した方法と基本的に同じです。また、sourceinsight が提供する転送定義やその他の機能を使用してその定義を確認したり、LKML (LinuxKernelMailList) を使用して確認したりすることもできます。動作しない場合は、質問して答えを求めることもできます (LKML と stackoverflow について知りたいですか? 情報を収集してください)。実際、あらゆる手段を講じれば、このマクロの意味を常に取得できます。CPU ごとに独立して使用される変数を定義します。

linux内核源码剖析_linux内核源码是什么语言_linux内核源码分析

コメントを一度に正確に記述できることに固執することはありません (各関数の具体的な実装プロセスを理解する必要さえありません。一般的な機能の意味を理解するだけです)。収集した情報と上記のコードの分析 コメントの意味を継続的に確立します (ここでは、ソース コード内の元のコメントと識別子の名前が非常に役に立ちます)。絶え間ない注釈、情報への絶え間ない参照、そして注釈の意味の絶え間ない変化によって。

源码

関係するすべてのソース コード ファイルに注釈を付けるだけで、次のような効果が得られます。

1.基本的には、ソース コード内のコード要素の意味を理解します。

2.基本的に、このモジュールに関係する主要なソース コード ファイルはすべて見つかりました。

以前に収集した情報とデータに基づいて分析するコードの全体的または構造的な説明と組み合わせることで、分析結果とデータを比較して、コードの理解を決定および修正できます。このように、簡単なコメントを通じて、ソースコードモジュール全体の主な構造を把握することができます。これにより、単純なアノテーションの基本的な目的も達成されます。

ステップ 4: 詳細なメモ

コードの簡単なコメントを完了すると、モジュールの分析が半分終わったと感じることができ、残りの内容は詳細な分析とコードの完全な理解です。単純なコメントではコード要素の特定の意味を必ずしも正確に説明できるとは限らないため、詳細なコメントが非常に必要です。このステップでは、次のことを明確にする必要があります:

1.変数定義を使用する場合。

2.マクロで定義したコードを使用する場合。

3.関数のパラメータと戻り値の意味。

4.関数の実行フローと呼び出し関係。

5.構造体配列の具体的な意味と使用条件。

関数の外側のコード要素の意味は基本的に単純なコメントで明らかであるため、このステップを詳細関数アノテーションと呼ぶこともできます。関数自体の実行フローとアルゴリズムが、この部分のアノテーションと分析の主なタスクです。

たとえば、cpufreq_ondemand ポリシーの実装アルゴリズム (関数 dbs_check_cpu 内) がどのように実装されるか。アルゴリズムの詳細を理解するには、関数で使用される変数と呼び出される関数を徐々に分析する必要があります。最良の結果を得るには、この複雑な関数の実行フローチャートと関数呼び出し関係図が必要です。これは最も直観的な表現形式です。

源码

このステップのコメントを通じて、基本的に、分析対象のコードの全体的な実装メカニズムを完全に把握できます。そして、すべての分析作業は 80% 完了したと感じられます。このステップは特に重要であり、分析対象のコードの内部モジュールの定義をよりよく理解できるように、アノテーション情報を十分に正確にするように努める必要があります。実際、Linux カーネルは、マクロ文型「module_init」および「module_exit」を使用してモジュール ファイルを宣言し、モジュールの内部サブ関数の定義は、モジュールの機能の完全な理解に基づいています。モジュールが正しく定義されている限り、モジュールが提供する外部関数と変数を把握できます (EXPORT_SYMBOL_GPL または EXPORT_SYMBOL によってインポートされたシンボルを使用)。モジュール内の識別子の依存関係を分析する次のステップに進むことができます。

ステップ 5: モジュールの内部識別子の依存関係

4番目のステップでコードモジュールを定義することで、モジュールを1つずつ「簡単に」分析できます。通常、ファイルの先頭にあるモジュールの入口関数と出口関数から開始できます (「module_init」と「module_exit」で宣言された関数は通常、ファイルの最後にあります) Linux カーネル ソース コード分析 によれば、それらが呼び出す関数 (自己定義またはモジュールの他の関数) と使用される主要な変数 (このファイル内のグローバル変数または他のモジュールの外部変数) は、「関数-変数-関数」依存関係図を描画します。これを識別子と呼びます。依存関係図。

実際、モジュール内の識別子の依存関係は単純なツリー構造ではなく、多くの場合、複雑なネットワーク関係になります。この時点で、コードに対する詳細なコメントの役割が明らかになります。関数自体の意味に従ってモジュールのサブ関数を定義し、各サブ関数の識別子依存ツリーを抽出します。

源码

識別子の依存関係分析を通じて、モジュールによって定義された関数がこれらの関数を呼び出していること、どの変数が使用されているか、モジュールのサブ関数間の依存関係 (どの関数と変数が共有されているかなど) を明確に示すことができます。

ステップ 6: モジュール間の相互依存性

すべてのモジュールの内部識別子の依存関係図が整理されると、モジュールが使用する他のモジュールの変数や関数に基づいてモジュール間の依存関係を簡単に取得できます。

linux内核源码是什么语言_linux内核源码剖析_linux内核源码分析

源码

cpufreqコードのモジュール依存関係は以下の関係で表すことができます。

源码

ステップ 7: モジュールアーキテクチャ図

モジュール間の依存関係図により、解析対象のコード全体におけるモジュールの状態や機能を明確に表現できます。これに基づいて、モジュールを分類し、コードのアーキテクチャ上の関係を整理できます。

源码

cpufreq のモジュール依存関係図に示されているように、すべての周波数変調戦略モジュールがコア モジュール cpufreq、cpufreq_stats、および freq_table に依存していることが明確にわかります。 3 つの依存モジュールをコードのコア フレームワークとして視覚化すると、これらの周波数変調戦略モジュールはこのフレームワーク上に構築され、ユーザー層との対話を担当します。コア モジュール cpufreq は、基礎となるシステムとの対話を担当するドライバーおよびその他の関連ソケットを提供します。したがって、次のモジュール アーキテクチャ図が得られます。

源码

実際、アーキテクチャ図はモジュールを無機的につなぎ合わせたものではなく、アーキテクチャ図の意味を豊かにするために参照するデータを組み合わせる必要もあります。したがって、ここでのアーキテクチャ図の詳細は、さまざまな人々の理解によって異なります。また、アーキテクチャ図本体の意味も基本的に同じです。これで、解析対象となるカーネルコードの解析作業はすべて完了しました。

4.まとめ

記事の冒頭で述べたように、カーネル コード全体を分析することは不可能です。したがって、分析対象のコードから情報を収集し、上記のプロセスに従ってコードの元ネタを分析することは、カーネルの本質を理解するために有効な方法です。特定のニーズに応じてカーネル コードを分析するこれらの方法により、Linux カーネルの世界にすぐに参入できる可能性が得られます。これらの方法を通じて、カーネルの他のモジュールの分析を続け、最終的には Linux カーネルについての独自の理解を包括的に取得し、Linux カーネルを学習するという目的を達成します。

最後に、カーネルを学習するための参考書を 2 冊お勧めします。 1 つは「Linux カーネルの設計と実装」で、読者に Linux カーネルの主な機能と実装について手早く簡潔に紹介します。ただし、読者を Linux カーネル コードの深淵に導くものではありません。この本は、カーネル アーキテクチャを理解し、Linux カーネル コードを始めるのに特に優れた参考書です。同時に、読者のカーネル コードへの関心も高まります。もう 1 つは、「Linux カーネルの徹底理解」です。なぜこの本の傑作についてもっと説明する必要があるのでしょうか。この本をよりよく学びたい場合は、カーネル コードと併せて読むのが最善であることをお勧めします。本書はカーネルコードについて詳しく解説しているので、コードと合わせて読むとカーネルコードの理解が深まります。同時に、カーネルコードを解析する過程で、参考となる情報も本書で見つけることができます。最後に、皆さんができるだけ早くカーネルの世界に入り、Linux がもたらす驚きを体験してほしいと願っています。

The above is the detailed content of In-depth analysis of the Linux kernel source code and exploration of the essence of the operating system. For more information, please follow other related articles on the PHP Chinese website!

Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn