曲径通幽论坛

标题: 获得当前进程描述符 | current [打印本页]

作者: beyes    时间: 2011-6-17 14:31
标题: 获得当前进程描述符 | current
内核:2.6.11
平台:x86 32位

进程内核态栈结构如下图所示:

上图中,thread_info 结构位于栈的底部,该结构定义为:
[C++] 纯文本查看 复制代码
struct thread_info {
    struct task_struct    *task;        /* main task structure */
    struct exec_domain    *exec_domain;    /* execution domain */
    unsigned long        flags;        /* low level flags */
    unsigned long        status;        /* thread-synchronous flags */
    __u32            cpu;        /* current CPU */
    __s32            preempt_count; /* 0 => preemptable, <0 => BUG */


    mm_segment_t        addr_limit;    /* thread address space:
                            0-0xBFFFFFFF for user-thead
                           0-0xFFFFFFFF for kernel-thread
                        */
    struct restart_block    restart_block;

    unsigned long           previous_esp;   /* ESP of the previous stack in case
                           of nested (IRQ) stacks
                        */
    __u8            supervisor_stack[0];
};

该结构保存了进程描述符中被频繁访问和需要快速访问的字段。该结构的第一个成员变量 task 记录了该结构属于哪一个进程描述符,可以通过该指针获得对应的进程描述符。

在内核中有一个宏 --- current ,通过它可以获得当前进程描述符。该宏定义在 include/asm-i386/current.h 中:
[C++] 纯文本查看 复制代码
#define current get_current()

get_current() 同样定义在 include/asm-i386/current.h 中:
[C++] 纯文本查看 复制代码
static inline struct task_struct * get_current(void)
{
    return current_thread_info()->task;
}

上面的 current_thread_info() 函数定 include/asm-i386/thread_info.h 中:
[C++] 纯文本查看 复制代码
/* how to get the thread information struct from C */
static inline struct thread_info *current_thread_info(void)
{
    struct thread_info *ti;
    __asm__("andl %%esp,%0; ":"=r" (ti) : "0" (~(THREAD_SIZE - 1)));
    return ti;
}

上面 THREAD_SIZE 定义在  include/asm-i386/current.h 中:
[C++] 纯文本查看 复制代码
#ifdef CONFIG_4KSTACKS
#define THREAD_SIZE            (4096)
#else
#define THREAD_SIZE        (8192)
#endif

THREAD_SIZE 表示配置内核时选择栈的大小,要么为 4K,要么为 8K 。这里假定为 8K,所以 ~(THREAD_SIZE - 1) 的值为 0xFFFFE000 ,也就是该数后面的 13 位均为 0 。

函数中的内联汇编中的 "0" 表示输入和输出均用相同的寄存器存放,输出结果放在 ti 这个变量中,最后返回这个变量。

andl %%esp,%0; 表示用 ~(THREAD_SIZE - 1) 和栈指针做与运算,也就是要将栈指针的后 13 位屏蔽,这样得到的结果正好是内核态栈中的最低地址,此处正是 task 指针所存放的地方。

内核态栈是这么定义的:
[C++] 纯文本查看 复制代码
union thread_union {
    struct thread_info thread_info;
    unsigned long stack[THREAD_SIZE/sizeof(long)];
};

这是个联合体,所以  thread_info 结构和 stack数组 共享内核态栈空间。联合体中的内容是从低地址开始存放的,也就是 thread_info 结构中的第一个成员 task 指针会存放在栈的最底部;而在 x86 体系下,栈的方向是从高往低增长的,而且内核栈 stack 占据的空间要比 thread_info 要大很多,这样就能够有效的防止两个共享一样空间的数据结构互相覆盖所造成的冲突。




欢迎光临 曲径通幽论坛 (http://www.groad.net/bbs/) Powered by Discuz! X3.2