通过alloc_task_struct()函数创建内核栈和task_struct结构空间,alloc_task_struct()函数定义为

     # define alloc_task_struct() kmem_cache_alloc(task_struct_cachep, GFP_KERNEL)

接着分配thread_info结构空间

ti = alloc_thread_info(tsk);

thread_info结构定义在asm/thread_info.h中

      struct thread_info {
struct task_struct *task;
struct exec_domain *exec_domain;
unsigned long flags;
unsigned long status;
__u32 cpu;
__s32 preempt_count;
mm_segment_t addr_limit;
struct restart_block restart_block;
unsigned long previous_esp;
__u8 supervisor_stack[0];
};

继续

*tsk = *orig;

为整个task_struct结构复制

再调用setup_thread_stack()函数为thread_info结构复制

      static inline void setup_thread_stack(struct task_struct *p, struct task_struct *org)
{
*task_thread_info(p) = *task_thread_info(org);
task_thread_info(p)->task = p;
}

其中

task_thread_info(p)->task = p;

thread_info结构中的task成员中存放的是指向当前进程task_struct结构的指针。

回到copy_process()函数,继续看:

      if (atomic_read(&p->user->processes) >=
p->signal-> rlim[RLIMIT_NPROC].rlim_cur) {
if (!capable(CAP_SYS_ADMIN) && !capable(CAP_SYS_RESOURCE) &&
p->user != &root_user)
goto bad_fork_free;
}
atomic_inc(&p->user->__count);
atomic_inc(&p->user->processes);
get_group_info(p->group_info);

首先看前面的两个if,第一个if里面的rlim数组包含在task_sturct数组中。对进程占用的资源数做出限制,rlim[RLIMIT_NPROC]限制了改进程用户可以拥有的总进程数量,如果当前用户所拥有的进程数量超过了规定的最大拥有进程数量,在2.4内核中就直接goto bad_fork_free了。第2个if使用了capable()函数来对权限做出检查,检查是否有权对指定的资源进行操作,该函数返回0则代表无权操作。该函数的定义在linux/capability.h中,其中包含了与之相对应的权限列表。

在task_struct结构中有一个指针user,该指针指向一个user_struct结构,一个用户的多个进程可以通过user指针共享该用户的资源信息,该结构定义在include/linux/sched.h中:

      struct user_struct {
atomic_t __count; /*统计用户拥有进程数量的计数器 */
atomic_t processes; /*统计用户拥有进程数 */
atomic_t files; /* 统计用户打开的文件数 */
atomic_t sigpending; /* 统计用户拥有的信号 */
#ifdef CONFIG_INOTIFY_USER
atomic_t inotify_watches; /* How many inotify watches does this user have? */
atomic_t inotify_devs; /* How many inotify devs does this user have opened? */
#endif
/* protected by mq_lock */
unsigned long mq_bytes; /* How many bytes can be allocated to mqueue? */
unsigned long locked_shm; /* How many pages of mlocked shm ? */
#ifdef CONFIG_KEYS
struct key *uid_keyring; /* UID specific keyring */
struct key *session_keyring; /* UID's default session keyring */
#endif
/* Hash table maintenance information */
struct list_head uidhash_list;
uid_t uid;
};

既然新创建了一个进程,自然要更新该用户的user_struct结构,累加相应的计数器,这个工作就由atomic_inc()函数完成,atomic_inc函数定义在include/asm-blackfin/atomic.h中:

      static __inline__ void atomic_inc(volatile atomic_t * v)
{
long flags;
local_irq_save(flags);
v->counter++;
local_irq_restore(flags);
}

函数保存当前各成员的标记,然后进行累加,最后更新各成员,完成累加计数器的操作。

继续看copy_process函数的代码:

      if (nr_threads >= max_threads)
goto bad_fork_cleanup_count;
if (!try_module_get(task_thread_info(p)->exec_domain->module))
goto bad_fork_cleanup_count;
if (p->binfmt && !try_module_get(p->binfmt->module))
goto bad_fork_cleanup_put_domain;
p->did_exec = 0;
delayacct_tsk_init(p); /* Must remain after dup_task_struct() */
copy_flags(clone_flags, p);
p->pid = pid_nr(pid);
retval = -EFAULT;
if (clone_flags & CLONE_PARENT_SETTID)
if (put_user(p->pid, parent_tidptr))
goto bad_fork_cleanup_delays_binfmt;
INIT_LIST_HEAD(&p->children);
INIT_LIST_HEAD(&p->sibling);
p->vfork_done = NULL;
spin_lock_init(&p->alloc_lock);
clear_tsk_thread_flag(p, TIF_SIGPENDING);
init_sigpending(&p->pending);

代码段

      if (nr_threads >= max_threads)
goto bad_fork_cleanup_count;

检查创建的进程是否超过了系统进程总量

      if (!try_module_get(task_thread_info(p)->exec_domain->module))
goto bad_fork_cleanup_count;

获得进程执行域

      if (p->binfmt && !try_module_get(p->binfmt->module))
goto bad_fork_cleanup_put_domain;

不同进程所执行的程序的格式也不一样,系统对不同格式的支持通过动态安装驱动模块实现,task_struct结构中有一个指向linux_binfmt结构的指针,获得进程执行程序映象。

      copy_flags(clone_flags, p);

调用copy_flags函数更新task_struct结构中flags成员。表明进程是否拥有超级用户权限的PF_SUPERPPRIV标志被清除,表明进程还没有exec()的PF_FORKNOEXEC被设置,相关实现代码也在fork..c中:

      static inline void copy_flags(unsigned long clone_flags, struct task_struct *p)
{
unsigned long new_flags = p->flags;
new_flags &= ~(PF_SUPERPRIV | PF_NOFREEZE);
new_flags |= PF_FORKNOEXEC;
if (!(clone_flags & CLONE_PTRACE))
p->ptrace = 0;
p->flags = new_flags;
}

接着p->pid = pid_nr(pid);获取一个PID

      p->vfork_done = NULL;
vfork()在调用copy_process()时,task_struct结构的vfork_done成员被设置为NULL,在回到do_fork()执行时vfork_done会指向一个特殊的地址,这在do_fork中可以清楚的看到。

继续走下去:

      p->utime = cputime_zero;
p->stime = cputime_zero;
p->sched_time = 0;
#ifdef CONFIG_TASK_XACCT
p->rchar = 0; /* I/O counter: bytes read */
p->wchar = 0; /* I/O counter: bytes written */
p->syscr = 0; /* I/O counter: read syscalls */
p->syscw = 0;
…………………..
开始漫长的对子进程task_struct结构的初始化
…………………..
…………………..
…………………..
…………………..

继续

      p->tgid = p->pid;
if (clone_flags & CLONE_THREAD)
p->tgid = current->tgid;


相关内容