1.dup_task_struct函数调用位置及其作用
调用位置: do_fork -> copy_process -> dup_task_struct
作用:复制一份task_struct结构体
2.函数主体流程
static struct task_struct *dup_task_struct(struct task_struct *orig)
struct task_struct *tsk;
struct thread_info *ti;
unsigned long *stackend;
int err;
prepare_to_copy(orig);
tsk = alloc_task_struct(); //创建新的子进程结构体
if (!tsk)
return NULL;
ti = alloc_thread_info(tsk);
if (!ti) {
free_task_struct(tsk);
return NULL;
err = arch_dup_task_struct(tsk, orig); //把orig中的内容完全复制给tsk,相当于*tsk = *orig
if (err)
goto out;
tsk->stack = ti;
err = prop_local_init_single(&tsk->dirties);
if (err)
goto out;
setup_thread_stack(tsk, orig);
/*为整个thread_info结构复制,并设置指针指向
thread_info里面有一个指向task_struct的指针 ,子进程指向子进程的,父进程指向父进程的,而现在,
这两个thread_info中的某个指针,都指向了父进程的task_struct,所以还要使得子进程thread_info的指针指向tsk的task_struct,
而不是 父进程的task_struct:task_thread_info(p)->task = p;*/
clear_user_return_notifier(tsk);
stackend = end_of_stack(tsk);
*stackend = STACK_END_MAGIC; /* for overflow detection */
#ifdef CONFIG_CC_STACKPROTECTOR
tsk->stack_canary = get_random_int();
#endif
/* One for us, one for whoever does the "release_task()" (usually parent) */
atomic_set(&tsk->usage,2);
atomic_set(&tsk->fs_excl, 0);
#ifdef CONFIG_BLK_DEV_IO_TRACE
tsk->btrace_seq = 0;
#endif
tsk->splice_pipe = NULL;
account_kernel_stack(ti, 1);
return tsk;
free_thread_info(ti);
free_task_struct(tsk);
return NULL;
在专业高速缓冲内存上
分配task_struct,并完成初始化
在普通内存中
分配thread_info及连续的两个页面,完成初始化
将task_struct和thread_info联系起来
1.dup_task_struct函数调用位置及其作用调用位置: do_fork -> copy_process -> dup_task_struct作用:复制一份task_struct结构体2.函数主体流程static struct task_struct *dup_task_struct(struct task_struct *orig){ struct task
一、Linux中的task_struct:
进程在内核源码中以数据结构task_struct的形式存在,其中有几个非常常见的属性字段
1、__state是进程的当前状态,-1是unrunnable,0是runnable, >0是stopped
2、Counter是进程拥有的时间片,当一个时钟中断到来,当前占有CPU的进程时间片会消耗1,进程调度函数schedule会会遍历任务队列选择时间片最大的进程上CPU
2.1、参照调度函数源码schedule可知,整体的调度策略是选择最长时间片的进程上CPU,直到进程
static struct task_struct *dup_task_struct(struct task_struct *orig)
struct task_struct *tsk; //sizeof(task_struct) = 3236;这个值是通过gdb得到的,
//可以看到单个的task_struct
先来看看task_struct结构体。
众所周知,task_struct结构体是用来描述进程的结构体,进程需要记录的信息都在其中,下面我们来看看其中的具体项目。结构体存储在linux/sched.h中。
具体的字段有volatile long state;
void *stack;
struct task_struct __rcu *real_parent;
struct task_s
相关函数与结构体
进程创建的do_fork中会调用copy_process函数,这个函数会调用 dup_task_struct 函数
\linux-4.13.16\kernel\fork.c
dup_task_struct函数
\linux-4.13.16\kernel\fork.c
dup_task_struct 调用函数 alloc_task_struct_node,分配一个 task_struct 对象,用于复制task_struct
alloc_task_struct_
linux内核中有个编译选项CC_STACKPROTECTOR用来开启GCC的stack-protector功能,
这个功能是在GCC4.1版本中引入,用来检测栈是否遭到溢出攻击。
目前我们用的版本中开启了这两个选项CONFIG_CC_STACKPROTECTOR、CONFIG_CC_STACKPROTECTOR_REGULAR。
编译器栈溢出保护原理:
函数栈存储结构,从
init_dup函数是Linux内核中的一个函数,其作用是复制一个打开文件描述符的副本。通常在多进程并发的场景中使用,可以让多个进程同时操作同一个文件,而不会相互影响。
具体来说,init_dup函数会首先查找当前进程中与给定文件描述符fd相对应的打开文件对象,然后创建一个新的文件描述符fd2,并将fd对应的文件对象复制一份给fd2。同时,fd2所属的文件表也会被更新,这样fd2和fd就可以独立操作相同的文件对象了。
在Linux内核的代码实现中,init_dup函数有以下代码:
int init_dup(struct file *file, unsigned int flags)
struct file *newfile = NULL;
int fd;
newfile = kmem_cache_alloc(file_cachep, GFP_KERNEL);
if (!newfile)
return -ENOMEM;
fd_install(fd, newfile);
fd_install()函数是一个内部函数,用于将file所代表的文件对象添加到进程的文件描述符表中,并返回一个新的文件描述符。
return fd;
该函数会首先使用kmem_cache_alloc函数从文件对象缓存中分配一个新的文件对象,然后通过fd_install函数将该文件对象添加到当前进程的文件描述符表中。最后返回该文件描述符的值。
总之,init_dup函数是Linux内核中非常重要的一个函数,在多进程并发操作文件的情况下发挥着重要的作用。其使用也非常广泛,可以在内核中的各种文件系统和设备驱动中看到它的身影。