16

Linuxカーネルから取得しこのコードスニペットについて誰かに説明してもらえますか?

/*
  * how to get the thread information struct from C
 */
 static inline struct thread_info *current_thread_info(void) __attribute_const__;

 static inline struct thread_info *current_thread_info(void)
 {
        register unsigned long sp asm ("sp");
        return (struct thread_info *)(sp & ~(THREAD_SIZE - 1));
}

質問:

  1. __attribute_const__ですか?
  2. これは何をしますか register unsigned long sp asm ("sp");
  3. なぜ(struct thread_info *)(sp & ~(THREAD_SIZE - 1));構造体へのポインタを返すのですか?
4

2 に答える 2

15
  1. 属性constは、返されたポインタがプログラムの期間中同じままであることを意味します。実際には、これは1つのスレッドの範囲にのみ当てはまりますが、コンパイラーがスレッド間のアクセスを最適化しようとする状況は考えられません。

  2. 変数を使用して、と呼ばれるハードウェアレジスタ、つまり現在のスタックポインタregisterにバインドします。このように、このレジスタに直接アクセスするためにコードをアセンブラで記述する必要はありません。asm("sp")sp

  3. THREAD_SIZEは定数であり、スレッドのスタックに割り当てられたメモリの量を示します。常に2の累乗である必要があると思います。たとえば、8キロバイトが一般的な値である可能性があります。

    次に、式~(THREAD_SIZE - 1)は実際のスタックアドレスを取り除くためのビットマスクを提供します。8 kBスタックの場合、はになります0xffffe000

    ビット単位でスタックポインタ値を使用することにより、スタックに割り当てられた最小のアドレスを取得します。このアーキテクチャでは、スレッド情報がそこに格納されます。これは単なる設計上の決定であり、情報を保存するために他の場所を使用することもできます。

    スタックポインタは、各スレッドが常に独自のスタックを持つため、スレッド情報を取得するのに役立ちます。

于 2012-08-30T09:09:40.430 に答える
8

Linuxのカーネルスタックのサイズは固定されています(THREAD_SIZE-2ページ、またはx86では8KB)。スレッドのstruct thread_infoforは、スタックのメモリブロックの一番下に保持されます。スタックは下向きに機能するため、スタックポインターは最初はメモリブロックの終わりを指し、データがスタックにプッシュされると、スタックポインターはメモリブロックの下部に向かって移動することに注意してください。もちろん、他のCPUアーキテクチャは他の技術を使用する場合があります。

したがって、現在のスタックポインター値を取得し、下位ビットをマスクするとstruct thread_info、現在のスタックを使用するスレッドのへのポインターを取得します。

この線:

register unsigned long sp asm ("sp");

sp変数をCPUレジスタにマップするようにGCCに指示しますsp(ここで16ビットのレジスタ名が使用されているのは奇妙に思えます-これは実際のLinuxソースツリーからのものですか?)。

__attribute_const__一般に、GCCがコンパイラーである場合と定義されます__attribute__((__const__))(Linuxカーネル用に他に何かありますか?)。これは、関数に副作用がないことをGCCに伝えます。実際には、関数はそれよりも少し強力です。関数は引数のみを使用し、それらの引数のみに基づいて値を返します。これにより、コンパイラーに最適化の機会が与えられる可能性があります。グローバル変数が変更されていない、または読み取られていないことを前提としています(したがって、コンパイラーは、「通常の」関数呼び出しのために更新する必要がある可能性のあるメモリーの更新を自由に延期できます)。

于 2012-08-30T09:14:56.407 に答える