無料Wikiサービス | デモページ
検索

アクセス数
最近のコメント
kprobe - ななし
ksetの実装 - スーパーコピー
カーネルスレッドとは - ノース
カーネルスレッドとは - nbyst
asmlinkageってなに? - ノース
asmlinkageってなに? - よろしく
はじめ - ノース
はじめ - ノース
はじめ - 楽打連動ユーザー
はじめ - 楽打連動ユーザー
Adsense
広告情報が設定されていません。

currentマクロ


currentマクロは、実行プロセスのタスク構造体のアドレスを取得するためのアーキテクチャ依存のマクロで、ここではIA-32といたします。currentはSPレジスターの下位11ビットマスクしたアドレスを返すことで、そのプロセスのタスク構造体を取得することを実現しています。
#define current         get_current()
#define get_current()   (current_thread_info()->task)

static inline struct thread_info *current_thread_info(void)
{
       return (struct thread_info *)
               (current_stack_pointer & ~(THREAD_SIZE - 1));
}

static inline unsigned long current_stack_pointer(void)
{
       unsigned long sp;
       asm("mov sp,%0; ":"=r" (sp));
       return sp;
}
これは、プロセス毎に独自のカーネルスタックを有しているから。ということが大前提にあるからです。forkでプロセス作成時、dup_task_structで作成するプロセスのタスク構造体を作成し、同時にalloc_thread_infoで作成したthread_info構造体を作成しています。このアドレスをタスク構造体のstackメンバーに設定しています。
static struct task_struct *dup_task_struct(struct task_struct *orig)
{
       struct task_struct *tsk;
       struct thread_info *ti;
・・・・・ 
       tsk = alloc_task_struct();
       if (!tsk)
               return NULL;
・・・・・ 
       ti = alloc_thread_info(tsk);
       if (!ti) {
               free_task_struct(tsk);
               return NULL;
       }
・・・・・ 
       tsk->stack = ti;
・・・・・
alloc_thread_infoはthread_info構造体を1ページ取得(スタックサイズにより2ページもあり。)します。従って、この先頭アドレスは必ず下位11ビットは0ということです。しかもその先頭には、このthread_infoを使用するtask_struct構造体が設定するようになっています。
struct thread_info {
       struct task_struct      *task;          /* main task structure */
       struct exec_domain      *exec_domain;   /* execution domain */
       unsigned long           flags;          /* low level flags */
       __u32                   status;         /* thread synchronous flags */
       __u32                   cpu;            /* current CPU */
       int                     preempt_count;  /* 0 => preemptable,
                                                  <0 => BUG */
       mm_segment_t            addr_limit;
       struct restart_block    restart_block;
       void __user             *sysenter_return;
#ifdef CONFIG_X86_32
       unsigned long           previous_esp;   /* ESP of the previous stack in
                                                  case of nested (IRQ) stacks
                                               */
       __u8                    supervisor_stack[0];
#endif
};
プロセスのスタックポインターに設定しているのは、copy_threadで行っています。ここではtask_pt_regsでthread_info構造体内のアドレスを取得し、それをプロセス構造体のthreadメンバーに設定しているようです。
int copy_thread(int nr, unsigned long clone_flags, unsigned long sp,
       unsigned long unused,
       struct task_struct * p, struct pt_regs * regs)
{
       struct pt_regs * childregs;
       struct task_struct *tsk;
       int err;

       childregs = task_pt_regs(p);
       *childregs = *regs;
       childregs->ax = 0;
       childregs->sp = sp;

       p->thread.sp = (unsigned long) childregs;
       p->thread.sp0 = (unsigned long) (childregs+1);
task_pt_regsマクロを見てみると、プロセス構造体のstackメンバーの先頭アドレスから、KSTK_TOPマクロでその最上位のアドレスを取得し、そこから8引いた値を返しています。スタックは下位に向かって伸びていくものです。これでこのプロセスはカーネルモード時、alloc_thread_infoで確保した、thread_info内の上位部領域から、スタックとして利用可能となるわけです。
#define task_stack_page(tsk)    ((tsk)->stack)

define task_pt_regs(task)                                             \
({                                                                     \
      struct pt_regs *__regs__;                                       \
      __regs__ = (struct pt_regs *)(KSTK_TOP(task_stack_page(task))-8); \
      __regs__ - 1;                                                   \
})

#define KSTK_TOP(info)                                                 \
({                                                                     \
      unsigned long *__ptr = (unsigned long *)(info);                 \
      (unsigned long)(&__ptr[THREAD_SIZE_LONGS]);                     \
})
従ってSPポインターは、ページブロックのthread_info内のアドレス範囲で増減するわけで、下位の11ビットをマスクすれば、その先頭アドレス。すなわちプロセス構造体のアドレスが取得できると言う具合のようです。

最終更新 2010/03/04 15:15:53 - north
(2010/03/04 15:15:53 作成)