5

今、RobertLoveの「LinuxKernelDevelopment3dEdition」という本を読んでいます。そこで彼は、task_struct構造体へのポインターを含み、私が理解したように、プロセスのカーネルスタックの一番下または一番上にあるthread_info構造体について書いています(アーキテクチャによって異なります)。私は最近までLinuxカーネルAPIに精通しておらず、current()メソッドの存在についても知りませんでした。current()メソッドが実際にどのように機能するかに関する本からの抜粋があります。

x86では、currentは、スタックポインタの最下位13ビットをマスクしてthread_info構造を取得することで計算されます。これは、current_thread_info()関数によって実行されます。アセンブリは次のように表示されます:movl $ -8192、%eax andl% esp、%eaxこれは、スタックサイズが8KBであることを前提としています.4KBスタックが有効になっている場合、8192の代わりに4096が使用されます。

私の質問は次のとおりです。

  1. ビットのセットとして表される10進値があるかどうかを知る限り、セットには最下位ビットが1つだけありますね。
  2. 魔法の数13は何ですか?

このトピックを読む人にとって、私が表明した質問は、作成者がメモリの割り当てと管理のプロセスを適切に理解していないという結論につながる可能性があります。わかりました。私の考えでは、スタックに割り当てられたメモリをビット(またはバイト)でいっぱいのリボンとして表すことができるという事実のために、それは正しいかもしれません。このすべてのバイトは、10進値として表される特定のメモリアドレスによってアクセス可能です。スタックの起点は最小のメモリアドレスであり、スタックのフィンはメモリアドレスの最大値です。しかし、どのように、たとえば、スタックの最後にあるthread_info構造体へのポインターを取得するには、ARBITRARYにあるスタックポインターの最下位13ビットをマスクします(正しく理解していれば、スタックのビットをマスクします)。ポインタアドレスは10進値で表されます)。

4

4 に答える 4

4

各プロセスは、8192 バイト境界に整列された 8192 バイトのカーネル スタックのみを取得するため、スタック ポインターがプッシュまたはポップによって変更されるたびに、下位 13 ビットのみが変更されます。2**13==8192。

于 2012-08-14T22:13:47.580 に答える
3

カーネルスタックには、上部に特別な構造体が含まれています -- thread_info :

 26 struct thread_info {
 27         struct task_struct      *task;          /* main task structure */
 28         struct exec_domain      *exec_domain;   /* execution domain */
 29         __u32                   flags;          /* low level flags */
 30         __u32                   status;         /* thread synchronous flags */
 31         __u32                   cpu;            /* current CPU */
 32         int                     preempt_count;  /* 0 => preemptable,
 33                                                    <0 => BUG */
 34         mm_segment_t            addr_limit;
 35         struct restart_block    restart_block;
 36         void __user             *sysenter_return;
 37 #ifdef CONFIG_X86_32
 38         unsigned long           previous_esp;   /* ESP of the previous stack in
 39                                                    case of nested (IRQ) stacks
 40                                                 */
 41         __u8                    supervisor_stack[0];
 42 #endif
 43         unsigned int            sig_on_uaccess_error:1;
 44         unsigned int            uaccess_err:1;  /* uaccess failed */
 45 };

したがって、を取得するには、ASM コードからGET_THREAD_INFOを使用してポインターtask_structを取得する必要があります。thread_info

183 /* how to get the thread information struct from ASM */
184 #define GET_THREAD_INFO(reg)     \
185         movl $-THREAD_SIZE, reg; \
186         andl %esp, reg

... またはC コードのcurrent_thread_infoを使用:

174 /* how to get the thread information struct from C */
175 static inline struct thread_info *current_thread_info(void)
176 {
177         return (struct thread_info *)
178                 (current_stack_pointer & ~(THREAD_SIZE - 1));
179 }

x86_32 と x86_64 の両方でandが 1 とTHREAD_SIZE定義されているため、結果は 8192 (2^13 または 1<<13) になることに注意してください。(PAGE_SIZE << THREAD_SIZE_ORDER)THREAD_SIZE_ORDERTHREAD_SIZE

于 2012-08-16T23:00:10.117 に答える
0

私の 2 ビット: 'current' の実装はアーキテクチャに依存することに注意してください。これまでの回答は x86 に焦点を当てています。thread_info を取得するためのさまざまな手段、したがって task_struct は、Linux OS 上の他のアーキテクチャによって採用されています。

たとえば、どうやら PPC はレジスタ (RISC であり、多くの GPR を備えていることを覚えておいてください) を使用して current の値を格納し、事実上、それをハードウェア コンテキストの一部にしています! これは非常に高速になります。

最新の x86 ポート (私は 4.1.0 カーネル ソースを調べました) は、CPU ごとのデータを使用して、高速かつロックレスな方法で現在の実装を行います。等々...

于 2015-11-10T07:35:36.403 に答える