1. カーネルソースコードに関する私の意見
Linux カーネル コードの膨大なサイズが多くの人々を「気後れさせている」のはまさにこのためであり、人々の Linux に対する理解は一般的なレベルにすぎません。 Linux を分析してオペレーティング システムの性質を詳しく知りたい場合は、カーネルのソース コードを読むのが最も効果的な方法です。優れたプログラマー Linux カーネル ソース コード分析 になるには、多くの練習とコードのコンパイルが必要であることは誰もが知っています。プログラミングは依然として重要であり、多くの場合、プログラミングのみを行う人は、自分の知識領域を簡単に制限してしまいがちです。知識の幅を広げたい場合は、他の人が書いたコード、特に自分よりも上級者が書いたコードにもっと触れる必要があります。これらの方法を通じて、私たちは自分自身の知識の輪の制限を抜け出し、他の人の知識の輪に足を踏み入れることができ、通常は短期間では理解するのが難しいと思われる情報についてさらに学ぶことができます。 Linux カーネルは、オープン ソース コミュニティの無数の「マスター」によって注意深く保守されており、それらの人々はトップ コードの専門家と呼ぶことができます。 Linux カーネルのコードを読むことで、カーネル関連の知識を学ぶだけでなく、プログラミング方法やコンピュータの理解を学び、肌で感じることの方が価値があると私は考えています。
私はプロジェクトを通じて Linux カーネルのソースコードの分析にも触れ、ソースコードの分析から多くの恩恵を受けてきました。関連するカーネルの知識を獲得しただけでなく、カーネル コードに対するこれまでの理解も変わりました。
1.カーネルのソースコードの分析は「手の届かない」わけではありません。カーネルのソースコード解析の難しさは、ソースコード自体にあるのではなく、より適切な方法や手法を使ってコードを解析する方法にあります。カーネルは複雑であるため、通常のデモ プログラムを分析するように main 関数から開始して段階的に分析することはできません。カーネルのソース コードを 1 つずつ「突破」するために、途中から介入する方法が必要です。これらの「オンデマンド」形式を使用すると、特定の詳細に囚われすぎずに、ソース コードの主要なスレッドを把握できるようになります。
2.芯のデザインが素敵です。カーネルの特殊なステータスにより、カーネルの実行効率が現在のコンピュータ アプリケーションのリアルタイム要件に応えるのに十分高くなければならないことが決まり、そのため、Linux カーネルは C 言語とアセンブリのハイブリッド プログラミングを使用します。そして、多くの場合、ソフトウェアの実行効率とソフトウェアの保守性が相反することは誰もが知っています。カーネルの効率を確保しながらカーネルの保守性を向上させる方法は、カーネル内のこれらの「美しい」設計に依存します。
3.驚くべきプログラミング手法。一般的なアプリケーション ソフトウェア設計の分野では、コーディングの状況はあまり強調されないかもしれません。開発者はソフトウェアの優れた設計により注意を払い、コーディングは単なる実装手段の問題です。斧を使って薪を割るのと同じで、何も必要はありません。考えすぎ。そして、これはカーネル内で確立されているわけではありません。優れたコーディング設計は、保守性を向上させるだけでなく、コードのパフォーマンスも向上させます。
カーネルに対する理解は人それぞれ異なります。カーネルに対する理解が深まるにつれ、カーネルの設計と実装についてさらに考えたり感じたりするようになります。したがって、この記事は、Linux カーネル ルームの外をさまよっているより多くの人々を Linux の世界に導き、カーネルの魔法と偉大さを個人的に体験してもらいたいと考えています。私はカーネル ソース コードの専門家ではありませんが、ソース コードの分析における自分の経験と洞察を共有し、それを必要とする人に参考と支援を提供したいと考えています。特にオペレーティング システムのカーネルに関しては、独自のささやかな努力に貢献する必要があります。さっそく(もう長文すぎて恥ずかしい~)、私自身の Linux カーネル ソース コード分析方法を共有しましょう。
2. カーネルのソースコードを入手するのは難しいですか?
本質的に、Linux カーネル コードを分析することは、他の人のコードを見ることと何ら変わりません。目の前にあるコードは通常、自分で書いたコードではないからです。まず簡単な例を見てみましょう。見知らぬ人があなたにランダムにプログラムを渡し、ソースコードを読んでそのプログラムの機能設計を説明してくださいと言われたら、自分のプログラミングスキルは大丈夫だと思っている人の多くは、これは何でもないと思うに違いありません。 、彼のコードを最初から最後まで辛抱強く読んでいる限り、間違いなく答えを見つけることができますが、これは実際に当てはまります。さて、仮定を変えてみましょう。この人が Linus で、彼があなたに提供したものが Linux カーネルのモジュールのコードだったとしても、それはまだそれほど簡単だと思いますか?躊躇する人も多いかもしれません。同じ見知らぬ人から与えられたコードに対して、私たちはなぜこれほど異なる感情を抱くのでしょうか (Linus があなたのことを知っているかどうかは考慮しません、笑~)。以下のような理由があると思います
1. Linux カーネル コードは、「外の世界」にとってはやや謎めいたものですが、非常に大きいため、目の前に置かれても使い始めるのが難しいかもしれません。たとえば、メイン関数が見つからないという非常に小さな理由から問題が始まる可能性があります。単純なデモ プログラムの場合、コードの意味を最初から最後まで解析できますが、カーネル コードを解析する方法はまったく効果がありません。なぜなら、誰も Linux コードを最初から最後まで読むことができないからです (実際には必要ないからです) 、そして使用するときは、それを見てください)。
2.小規模なソフトウェアのコードに触れる人もたくさんいますが、そのほとんどはアプリケーション プロジェクトであり、コードの形式と意味は、頻繁に触れるビジネス ロジックに関連しています。カーネル コードは異なります。カーネル コードが処理する情報のほとんどは、コンピューターの最下層と密接に関連しています。たとえば、オペレーティング システム、コンパイラ、アセンブリ、アーキテクチャなどに関する関連知識が不足している場合も、カーネル コードを読むことが難しくなります。
3.カーネル コードを分析する方法は十分に合理的ではありません。大量の複雑なカーネル コードに直面する場合、グローバルな観点から Linux Mint を使い始めないと、コード詳細の泥沼にはまりやすくなります。結局のところ、カーネル コードは巨大であり、その設計原則とアーキテクチャも存在します。そうでないと、カーネル コードを保守するのは誰にとっても悪夢になるでしょう。コードモジュールの全体的な設計思想を明確にしてから、コードの実装を分析すると、ソースコードの分析が簡単で楽しくなるかもしれません。
これはこれらの問題に対する私の個人的な理解です。これまで小規模なソフトウェア プロジェクトに携わったことがない場合、Linux カーネル コードを分析することは、小規模なプロジェクトでの経験を積む良い機会になるかもしれません (実際、Linux コードは、私がこれまでに経験した最大のプロジェクトです!)。コンピューターの基礎的な側面を十分に理解していない場合は、分析と学習を同時に行うことで基礎的な知識を蓄積することを選択できます。最初はコードの分析の進みが少し遅いかもしれませんが、知識が蓄積されていくと、Linux カーネルの「ビジネス ロジック」に対する理解が徐々に明確になっていきます。最後のポイントは、グローバルな視点から分析のソースコードを使いこなす方法です。これも私が皆さんと共有したい経験です。
3. カーネルソースコードの解析方法
ステップ 1: データ収集
人が新しいものを理解するという観点から見ると、物事の本質を探る前に、新しいものを理解するプロセスが必要であり、このプロセスによって新しいものの予備的な概念が形成されます。例えば、ギターを習いたい場合、まずギターを弾くには基本的な視唱、簡略記法、五線などの基礎知識が必要であることを理解し、次に二胡の演奏方法や運指を学び、ようやくギターを始める必要があります。ギターの練習中。
カーネルコードの分析にも同じことが当てはまります。まず、分析対象のコードに含まれるコンテンツを特定する必要があります。プロセスの同期とスケジューリングのコード、ビデオ メモリ管理のコード、デバイス管理のコード、システム起動のコードなどですか。カーネルの複雑さにより、すべてのカーネル コードを一度に分析することはできないため、合理的な分業を行う必要があります。アルゴリズム設計が示すように、大きな問題を解決するには、まずそれに含まれる部分的な問題を解決する必要があります。
分析対象のコード範囲を特定したら、手元にあるすべてのリソースを使用して、コードのこの部分の全体的な構造と一般的な機能をできるだけ包括的に理解できます。
ここで言及されているすべてのリソースは、Baidu、Google の小型オンライン検索エンジン、オペレーティング システムの原理の教科書や専門書、他者によって提供された経験や情報、さらには Linux ソース コードによって提供されるドキュメント、コメント、ソース コードを指します。識別子の名前(コード内の識別子の命名を過小評価しないでください。重要な情報が提供される場合があります)。実際、ここでのすべてのリソースは、考えられるすべての利用可能なリソースを指します。実際、これらの情報収集方法で必要なすべての情報を入手できる可能性はほとんどありません。私たちは、できる限り包括的な情報を収集したいと考えています。より包括的な情報が収集されるほど、コードの分析プロセスでより多くの情報を使用できるようになり、分析プロセスの難易度が軽減されるためです。
ここでは、Linux の周波数変換メカニズムによって実装されたコードを分析したいとします。これまでのところ、この用語は文字通りの意味しかわかっていませんが、CPU の周波数調整に関連していると推測できます。情報収集を通じて、次の関連情報を取得できるはずです:
1. CPUFreq メカニズム。
2.パフォーマンス、省電力、ユーザースペース、オンデマンド、保守的な周波数調整戦略。
3. /ドライバー/cpufreq/。
4. /ドキュメント/cpufreq。
5. Pstate と Cstate。
……
Linux カーネル コードを分析するときにこの種の情報を収集できれば、それは非常に「幸運」であると言えるでしょう。確かに Linux カーネルに関する情報は .NET や JQuery ほど豊富ではありませんが、強力な検索エンジンや関連する研究資料がなかった 10 年以上前に比べれば、まさに「大豊作」の時代と呼ぶべきでしょう。簡単な「検索」 (1 ~ 7 日かかる場合があります) によって、コードのこの部分が配置されているソース コード ファイル ディレクトリも見つかりました。この種の情報はまさに「貴重」であると言わざるを得ません。
ステップ 2: ソースコードの場所
データ収集から、ソース コードに関連するソース コード ディレクトリを見つけることができたのは「幸運」でした。これは、このディレクトリ内のソース コードを実際に分析しているという意味ではありません。見つかったディレクトリが散在している場合もあれば、特定のマシンに関連するコードが多数含まれている場合もあります。そのため、マシンに関連する特殊なコードよりも、分析対象のコードの主要なメカニズムに関心があることがあります (これはカーネルの性質をより深く理解するのに役立ちます)。そのためには、情報の中からコードファイルが含まれる情報を慎重に選択する必要があります。実際、このステップは一度に完了する可能性は低く、分析対象のすべてのソース コード ファイルを一度に選択でき、どれも欠落しないという保証は誰にもできません。ほとんどのモジュールに関連するコア ソース ファイルを把握できれば、後でコードを詳細に分析することで自然にそれらを見つけることができます。
上記の例に戻り、/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 を簡単に見つけることができます。 。
検索された情報の流れの方向に従って、分析が必要なソースコードファイルを完全に見つけることができます。すべてのソース コード ファイルを見つける必要はなく、作業の一部をコードの分析プロセスに延期できるため、ソース コードを見つける手順はそれほど重要ではありません。ソース コード ファイルの一部を見つけることも、ソース コードを分析するための基礎となります。
ステップ 3: 簡単なコメント
見つかったソース コード ファイルで、各変数、マクロ、関数、構造、その他のコード要素の一般的な意味と機能を分析します。これを単純なコメントと呼ぶのは、この部分のコメント作業が非常に単純であるという意味ではなく、この部分のコメントは、大まかに意味を説明するものであれば、あまり詳しく説明する必要はないという意味です。関連するコード要素。それどころか、ここでの作業は、分析プロセス全体の中で最も難しいステップであることは言うまでもありません。カーネル コードを深く掘り下げるのは初めてなので、特に初めてカーネル ソース コードを分析する人にとっては、多くのなじみのない GNU C 文パターンと圧倒的なマクロ定義に非常にがっかりするでしょう。この時点で、落ち着いてそれぞれの重要な困難を理解していれば、将来同じような困難に遭遇したときに退却を余儀なくされることはありません。さらに、カーネルに関連する他の知識も木のように拡大し続けます。
たとえば、「DEFINE_PER_CPU」マクロの使用は、cpufreq.c ファイルの先頭に表示されます。この情報を参照することで、このマクロの意味と機能を基本的に理解できます。ここで使用する方法は、以前にデータを収集するために使用した方法と基本的に同じです。また、sourceinsight が提供する転送定義やその他の機能を使用してその定義を確認したり、LKML (LinuxKernelMailList) を使用して確認したりすることもできます。機能しない場合は、質問して答えを求めることもできます (LKML と stackoverflow について知りたいですか? 情報を収集してください)。実際、あらゆる手段を講じれば、このマクロの意味を常に取得できます。CPU ごとに独立して使用される変数を定義します。
コメントを一度に正確に記述できることに固執することはありません (各関数の具体的な実装プロセスを理解する必要さえありません。一般的な機能の意味を理解するだけです)。収集した情報と上記のコードの分析 コメントの意味を継続的に確立します (ここでは、ソース コード内の元のコメントと識別子の名前が非常に役に立ちます)。継続的な注釈、情報への継続的な参照、および注釈の意味の継続的な変化を通じて。
関係するすべてのソース コード ファイルに注釈を付けるだけで、次のような効果が得られます。
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: モジュール間の相互依存性
すべてのモジュールの内部識別子の依存関係図が整理されると、モジュールが使用する他のモジュールの変数や関数に基づいてモジュール間の依存関係を簡単に取得できます。
cpufreqコードのモジュール依存関係は以下の関係で表すことができます。
ステップ 7: モジュールアーキテクチャ図
モジュール間の依存関係図により、解析対象のコード全体におけるモジュールの状態や機能を明確に表現できます。これに基づいて、モジュールを分類し、コードのアーキテクチャ上の関係を整理できます。
cpufreq のモジュール依存関係図に示されているように、すべての周波数変調戦略モジュールがコア モジュール cpufreq、cpufreq_stats、および freq_table に依存していることが明確にわかります。 3 つの依存モジュールをコードのコア フレームワークとして視覚化すると、これらの周波数変調戦略モジュールはこのフレームワーク上に構築され、ユーザー層との対話を担当します。コア モジュール cpufreq は、基礎となるシステムとの対話を担当するドライバーおよびその他の関連ソケットを提供します。したがって、次のモジュール アーキテクチャ図が得られます。
実際、アーキテクチャ図はモジュールを無機的につなぎ合わせたものではなく、アーキテクチャ図の意味を豊かにするために参照するデータを組み合わせる必要もあります。したがって、ここでのアーキテクチャ図の詳細は、さまざまな人々の理解によって異なります。また、アーキテクチャ図本体の意味も基本的に同じです。これで、解析対象となるカーネルコードの解析作業はすべて完了しました。
4.まとめ
記事の冒頭で述べたように、カーネル コード全体を分析することは不可能です。したがって、分析対象のコードから情報を収集し、上記のプロセスに従ってコードの元ネタを分析することは、カーネルの本質を理解するために有効な方法です。特定のニーズに応じてカーネル コードを分析するこれらの方法により、Linux カーネルの世界にすぐに参入できる可能性が得られます。これらの方法を通じて、カーネルの他のモジュールの分析を続け、最終的には Linux カーネルについての独自の理解を包括的に取得し、Linux カーネルを学習するという目的を達成します。
最後に、カーネルを学習するための参考書を 2 冊お勧めします。 1 つは「Linux カーネルの設計と実装」で、読者に Linux カーネルの主な機能と実装について手早く簡潔に紹介します。ただし、読者を Linux カーネル コードの深淵に導くものではありません。この本は、カーネル アーキテクチャを理解し、Linux カーネル コードを始めるのに特に優れた参考書です。同時に、読者のカーネル コードへの関心も高まります。もう 1 つは、「Linux カーネルの徹底理解」です。なぜこの本の傑作についてもっと説明する必要があるのでしょうか。この本をよりよく学びたい場合は、カーネル コードと併せて読むのが最善であることをお勧めします。本書はカーネルコードについて詳しく解説しているので、コードと合わせて読むとカーネルコードの理解が深まります。同時に、カーネルコードを解析する過程で、参考となる情報も本書で見つけることができます。最後に、皆さんができるだけ早くカーネルの世界に入り、Linux がもたらす驚きを体験してほしいと願っています。
以上がLinux カーネルのソース コードを徹底的に分析し、オペレーティング システムの本質を探求するの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。