fork.c函数部分代码分析
来源:优易学  2011-12-22 17:41:51   【优易学:中国教育考试门户网】   资料下载   IT书店

  在内核代码 2.6.15.5中/kernel/fork.c第1255-1261中有如下代码:

  1. p = copy_process(clone_flags, stack_start, regs, stack_size, parent_tidptr, child_tidptr, pid);

  2. if (!IS_ERR(p)) {

  3.        struct completion vfork;

  4 .        if (clone_flags & CLONE_VFORK) {

  5.            p->vfork_done = &vfork;

  6.            init_completion(&vfork);

  7.        }

  为了方便描述我在这段代码上加了行号。

  第一行首先通过copy_process()函数完成具体的进程创建工作,返回值类型为task_t类型。

  第2行用函数 IS_ERR()分析copy_process()的返回值是否正确。如果正确则执行第3-7行代码。

  这里分析一下接下来这几行代码:

  struct completion vfork;           //定义struct completion 类型的变量 vfork;

  关于struct completion的定义如下:

  struct completion {

  unsigned int done;

  wait_queue_head_t wait;

  }

  第4行判断clone_flags中是否有CLONE_VFORK标志。如果有则执行下面的的代码:

  p->vfork_done = &vfork;

  init_completion(&vfork);

  在task_struct结构体中vfork_done是这样定义的:

  struct completion * vfork_done;

  函数init_completion()定义如下:

  static inline void init_completion(struct completion *x)

  {

  x->done = 0;

  init_waitqueue_head(&x->wait);

  }

  这个函数的作用是在进程创建的最后阶段,父进程会将自己设置为不可中断状态,然后睡眠在

  等待队列上(init_waitqueue_head()函数 就是将父进程加入到子进程的等待队列),等待子进程的唤醒。

  init_waitqueue_head()函数定义如下:

  static inline void init_waitqueue_head(wait_queue_head_t *q)

  {

  spin_lock_init(&q->lock);

  INIT_LIST_HEAD(&q->task_list);

  }

  spin_lock_init()定义如下:

  #define spin_lock_init(lock) do { *(lock) = SPIN_LOCK_UNLOCKED;}  while(0);

  wait_queue_head_t 定义如下:

  struct __wait_queue_head {

  spinlock_t lock;

  struct list_head task_list;

  }

  typedef struct __wait_queue_head wait_queue_head_t;

  INIT_LIST_HEAD(ptr) do { \

  (ptr)->next = (ptr); (ptr) ->prev = (ptr);} while(0);

  我们可以这么看vfork

  struct completion {

  unsigned int done;

  spinlock_t lock;

  struct list_head task_list;

  }

  最终结果;

  done = 0;

  lock = SPIN_LOCK_UNLOCKED;

  task_list.prev = task_list;

  task_list.next = task_list;

  p->vfork_done = &vfork;

  至此这段代码只是对当前子进程的等待对列进行了初始化。

  在fork.c的1281行还有这样的代码:

  if (clone_flags & CLONE_VFORK) {

  wait_for_completion(&vfork);

  .......

  }

  这时才将当前进程加入到了子进程的等待队列。

  下面是wait_for_completion()函数的定义:

  void fastcall __sched wait_for_completion(struct completion *x)

  {

  might_sleep();

  spin_lock_irq(&x->wait.lock);

  if (!x->done) {

  DECLARE_WAITQUEUE(wait, current);

  wait .flags |= WQ_FLAG_EXCLUSIVE;

  __add_wait_queue_tail(&x->wait, &wait);

  do {

  __set_current_state(TASK_UNINTERRUPTIBLE);

  spin_unlock_irq(&x->wait.lock);

  schedule();

  spin_lock_irq(&x->wait.lock);

  } while (!x->done);

  __remove_wait_queue(&x->wait, &wait);

  }

  x->done--;

  spin_unlock_irq(&x->wait.lock);

  }

  这里关于fastcall和__sched的定义如下(分别定义在内核以下两个文件中

  include/asm-i386/linkage.h

  kernel/sched.h

  ):

  #define fastcall __attribute__((regparm(3)))

  #define __sched __attribute__((__section__(".sched.text")))

  这两个宏定义使用了GNU C扩展。

  GNU C 允许声明函数,变量和类型的特殊属性,以便手工的代码和更仔细的代码检查。要指定一个声明的属性,在声明后写:

  __attribute__((ATTRIBUTE))

  其中ATTRIBUTE是属性说明。其中属性section用于函数和变量,其作用是:通常编译器将函数放在.text节,变量放在.data或.bss节,用section属性,可以让编译器将函数或变量放在指定的节中。

  这样连接器可以将相同节的代码或数据安排在一起。这在linux内核中是很常见的。

责任编辑:小草

文章搜索:
 相关文章
热点资讯
热门课程培训