「LDD3」を読み直してみると、無視していた「カーネルのスタックは非常に小さいので、4096 バイトのページしかない可能性があります。」という文を見つけました。この文に対して、プロセスの「カーネル スタック」について簡単に調べました。
プロセスの「カーネル スタック」とは何ですか? 各プロセスのライフサイクルでは、システムコールを通じて必然的にプロセスがカーネル内に閉じ込められます。システム コールを実行し、カーネルでトラップした後、これらのカーネル コードによって使用されるスタックは、ユーザー空間の元のスタックではなく、プロセスの「カーネル スタック」であるカーネル空間のスタックになります。
たとえば、単純なキャラクター ドライバーは open()
メソッドを実装します。このドライバーがマウントされた後、アプリケーションは glib ライブラリを通じて Linux open()
システム コールを呼び出します。システム コールが実行されてカーネルにトラップされると、プロセッサは特権モードに移行します (具体的な移行メカニズムはプロセッサ アーキテクチャによって異なります。たとえば、ARM の場合、通常モードとユーザー モードのスタック ポインタ (SP) は別のレジスタ)。このとき使用されるスタックポインタはカーネルスタックポインタであり、カーネルがプロセスごとに割り当てたカーネルスタック領域を指します。
カーネル スタックの役割 私の個人的な理解は、カーネルに入った後、システム コールには関数呼び出しや自動変数もあり、これらにはスタックのサポートが必要です。ユーザー空間スタックは明らかに安全ではないため、カーネル スタックのサポートが必要です。さらに、カーネル スタックは、システム コールの前に一部のアプリケーション層情報 (ユーザー空間スタック ポインターやシステム コール パラメーターなど) を保存するためにも使用されます。
カーネル スタックとプロセス構造間の関連付け 各プロセスは、作成時にカーネル スタック スペースを取得します。カーネル スタックとプロセスの対応は、次の 2 つの構造体のポインタ メンバーによって完了します。 (1) struct task_struct Linux のプロセス管理を学ぶ際に必ず学習する必要がある構造体。これはカーネル内のプロセスを表し、プロセスのすべてのステータス情報を記録します。この構造は Sched.h (include\linux) で定義されています。メンバ void *stack
があり、これは以下のカーネル スタック構造の「底部」を指します。システムの実行中、マクロ current
は現在のプロセスの struct task_struct
構造を取得します。
(2) カーネルスタック構造の結合 thread_union
リーリー構造体 thread_info は、プロセス コンテキスト情報を含むプロセス情報の一部を記録する構造体です。
リーリーキーはタスク メンバーであり、作成されたプロセスの struct task_struct 構造体を指します
スタック メンバーはカーネル スタックです。ここから、カーネル スタック スペースと thread_info がスペースを共有していることがわかります。カーネル スタックがオーバーフローすると、thread_info が破棄され、システムがクラッシュします~~~
カーネル スタック - struct thread_info - struct task_struct の関係を次の図に示します。
カーネルスタックの生成
プロセスが作成されると、フォーク ファミリのシステム コールによってカーネル スタックと struct task_struct にそれぞれスペースが割り当てられます。呼び出しプロセスは次のとおりです:
フォークファミリーのシステムコール—>do_fork—>copy_process—>dup_task_struct
dup_task_struct 関数内:
リーリーalloc_task_struct は、カーネルのスラブ アロケーターを使用して、作成されるプロセスに struct task_struct のスペースを割り当てます。
Alloc_thread_info は、カーネルのパートナー システムを使用して、作成されるプロセスにカーネル スタック (ユニオン thread_union) スペースを割り当てます
次の tsk->stack = ti; ステートメントは、struct task_struct およびカーネル スタックに関連しています
setup_thread_stack(tsk, orig); では、カーネル スタックと struct task_struct が関連付けられます。
リーリー
カーネルスタックサイズ
カーネルスタック領域はプロセスごとに割り当てられるため、大量に割り当てることはできません。このサイズはアーキテクチャに依存し、通常はページ単位で測定されます。実際、これは上で見た THREAD_SIZE であり、この値は通常 4K または 8K です。 ARM アーキテクチャの場合、これは Thread_info.h (arch\arm\include\asm)、 で定義されます。
リーリー
つまり、ARM のカーネル スタックは 8KB
(カーネル) ドライバーをプログラミングするときに注意する必要がある問題:
スタック スペースの制限のため、ドライバー (特にシステム コールで使用される低レベル関数) を作成するときは、再帰アルゴリズムやローカル自動変数のサイズなど、大量のスタック スペースを消費するコードを避けるように注意する必要があります。定義など
以上がLinux プロセスのカーネル スタックを理解するの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。