kernel_thread

kernel_thread定义(kernel/fork.c):

/** Create a kernel thread.*/
pid_t kernel_thread(int (*fn)(void *), void *arg, unsigned long flags)
{struct kernel_clone_args args = {.flags          = ((lower_32_bits(flags) | CLONE_VM |CLONE_UNTRACED) & ~CSIGNAL),.exit_signal    = (lower_32_bits(flags) & CSIGNAL),.stack          = (unsigned long)fn,.stack_size     = (unsigned long)arg,};return _do_fork(&args);
}

kernel_thread参数:
    int (*fn)(void *): 调用函数
    void *arg: 函数调用参数
    unsigned long flags:线程标志

进入 _do_fork:

long _do_fork(struct kernel_clone_args *args)
{u64 clone_flags = args->flags;struct completion vfork;struct pid *pid;struct task_struct *p;int trace = 0;long nr;
...p = copy_process(NULL, trace, NUMA_NO_NODE, args);

进入copy_process:

/*   #define CSIGNAL         0x000000ff      /* signal mask to be sent at exit */
#define CLONE_VM        0x00000100      /* set if VM shared between processes */
#define CLONE_FS        0x00000200      /* set if fs info shared between processes */
#define CLONE_FILES     0x00000400      /* set if open files shared between processes */
#define CLONE_SIGHAND   0x00000800      /* set if signal handlers and blocked signals shared */
#define CLONE_PIDFD     0x00001000      /* set if a pidfd should be placed in parent */
#define CLONE_PTRACE    0x00002000      /* set if we want to let tracing continue on the child too */
#define CLONE_VFORK     0x00004000      /* set if the parent wants the child to wake it up on mm_release */
#define CLONE_PARENT    0x00008000      /* set if we want to have the same parent as the cloner */
#define CLONE_THREAD    0x00010000      /* Same thread group? */
#define CLONE_NEWNS     0x00020000      /* New mount namespace group */
#define CLONE_SYSVSEM   0x00040000      /* share system V SEM_UNDO semantics */
#define CLONE_SETTLS    0x00080000      /* create a new TLS for the child */
#define CLONE_PARENT_SETTID     0x00100000      /* set the TID in the parent */
#define CLONE_CHILD_CLEARTID    0x00200000      /* clear the TID in the child */
#define CLONE_DETACHED          0x00400000      /* Unused, ignored */
#define CLONE_UNTRACED          0x00800000      /* set if the tracing process can't force CLONE_PTRACE on this clone */
#define CLONE_CHILD_SETTID      0x01000000      /* set the TID in the child */
#define CLONE_NEWCGROUP         0x02000000      /* New cgroup namespace */
#define CLONE_NEWUTS            0x04000000      /* New utsname namespace */
#define CLONE_NEWIPC            0x08000000      /* New ipc namespace */
#define CLONE_NEWUSER           0x10000000      /* New user namespace */
#define CLONE_NEWPID            0x20000000      /* New pid namespace */
#define CLONE_NEWNET            0x40000000      /* New network namespace */
#define CLONE_IO                0x80000000      /* Clone io context */
*/// 不允许与其他命名空间中的进程共享根目录
if ((clone_flags & (CLONE_NEWNS|CLONE_FS)) == (CLONE_NEWNS|CLONE_FS))                                      return ERR_PTR(-EINVAL); if ((clone_flags & (CLONE_NEWUSER|CLONE_FS)) == (CLONE_NEWUSER|CLONE_FS))return ERR_PTR(-EINVAL);// 分配的线程只能在线程组内启动,线程组必须共享信号
if ((clone_flags & CLONE_THREAD) && !(clone_flags & CLONE_SIGHAND))return ERR_PTR(-EINVAL);// 线程组共享虚拟内存空间(线程或子进程共享父进程的内存空间)
if ((clone_flags & CLONE_SIGHAND) && !(clone_flags & CLONE_VM))return ERR_PTR(-EINVAL);//  define SIGNAL_UNKILLABLE       0x00000040 /* for init: ignore fatal signals */
if ((clone_flags & CLONE_PARENT) &&current->signal->flags & SIGNAL_UNKILLABLE)return ERR_PTR(-EINVAL);// 线程不能同时分配新的用户空间和pid命名空间,并且current的pid命名空间与它的子pid命名空间是同一个(同一个用户下)
if (clone_flags & CLONE_THREAD) {if ((clone_flags & (CLONE_NEWUSER | CLONE_NEWPID)) ||(task_active_pid_ns(current) != nsp->pid_ns_for_children))return ERR_PTR(-EINVAL);}// 不允许线程或当前子进程在别的时间命名空间中
if (clone_flags & (CLONE_THREAD | CLONE_VM)) {if (nsp->time_ns != nsp->time_ns_for_children)return ERR_PTR(-EINVAL);}// 清空信号标志
sigemptyset(&delayed.signal);
INIT_HLIST_NODE(&delayed.node);// 锁定当前信号
spin_lock_irq(&current->sighand->siglock);// fork期间收集多进程信号(这段时间不会触发信号执行)if (!(clone_flags & CLONE_THREAD))hlist_add_head(&delayed.node, &current->signal->multiprocess);
// 恢复信号接收
recalc_sigpending();
// 解锁当前信号
spin_unlock_irq(&current->sighand->siglock);// 如果信号为挂起状态
if (signal_pending(current))goto fork_out;retval = -ENOMEM;// 为进程/线程分配task_struct结构对象和内核栈,如果开启CONFIG_VMAP_STACK使用__vmalloc_node_range分配栈(这些内存在物理上可能是不连续的),否则使用alloc_pages_node分配栈p = dup_task_struct(current, node);if (!p)goto fork_out;... retval = copy_creds(p, clone_flags);if (retval < 0)goto bad_fork_free;

检查创建类型,分配task_struct结构对象和内核栈,进入copy_creds:

/** Copy credentials for the new process created by fork()** We share if we can, but under some circumstances we have to generate a new* set.** The new process gets the current process's subjective credentials as its* objective and subjective credentials*/
int copy_creds(struct task_struct *p, unsigned long clone_flags)
{struct cred *new;int ret;...new = prepare_creds();if (!new)return -ENOMEM;// 如果指定创建用户空间(参考userns_operations,cred绑定用户空间,NFS中,用户对文件的访问权限用数据结构nfs_access_entry表示)if (clone_flags & CLONE_NEWUSER) {ret = create_user_ns(new);if (ret < 0)goto error_put;}...atomic_inc(&new->user->processes);p->cred = p->real_cred = get_cred(new);alter_cred_subscribers(new, 2);validate_creds(new);return 0;error_put:put_cred(new);return ret;
}

创建用户空间,回到copy_process:

说明:
  linux中,任务的所有凭据都保存在(uid、gid)或通过(组、密钥、LSM安全性)一个"结构cred"类型的重新计算结构中。每个任务都通过其task_struct中名为"cred"的指针指向其凭据

delayacct_tsk_init(p);  /* Must remain after dup_task_struct() */
p->flags &= ~(PF_SUPERPRIV | PF_WQ_WORKER | PF_IDLE);
p->flags |= PF_FORKNOEXEC;
INIT_LIST_HEAD(&p->children);
INIT_LIST_HEAD(&p->sibling);
// 默认没有启动
rcu_copy_process(p);p->vfork_done = NULL;
spin_lock_init(&p->alloc_lock);
// 清空信号标志
init_sigpending(&p->pending);...// task_io_accounting:用于记录单个任务的IO统计
task_io_accounting_init(&p->ioac);
// 清空task_struct中的mm部分
acct_clear_integrals(p);// posix CPU定时器相关数据的容器
posix_cputimers_init(&p->posix_cputimers);p->io_context = NULL;
// 任务审核上下文
audit_set_context(p, NULL);
//初始化cgroup相关字段,任务与init_css_set相关联,提高cgroup性能
cgroup_fork(p);#ifdef CONFIG_LOCKDEP// 内核死锁检测模块lockdep_init_task(p);
#endif/* Perform scheduler related setup. Assign this task to a CPU. */
// 将进程和指定cpu绑定,p->wake_cpu用于唤醒该进程
retval = sched_fork(clone_flags, p);
if (retval)goto bad_fork_cleanup_policy;retval = perf_event_init_task(p);
if (retval)goto bad_fork_cleanup_policy;
retval = audit_alloc(p);
if (retval)goto bad_fork_cleanup_perf;
/* copy all the process information */
shm_init_task(p);
retval = security_task_alloc(p, clone_flags);
if (retval)goto bad_fork_cleanup_audit;
retval = copy_semundo(clone_flags, p);
if (retval)goto bad_fork_cleanup_security;
retval = copy_files(clone_flags, p);
if (retval)goto bad_fork_cleanup_semundo;
retval = copy_fs(clone_flags, p);
if (retval)goto bad_fork_cleanup_files;
retval = copy_sighand(clone_flags, p);
if (retval)goto bad_fork_cleanup_fs;
retval = copy_signal(clone_flags, p);
if (retval)goto bad_fork_cleanup_sighand;
retval = copy_mm(clone_flags, p);
if (retval)goto bad_fork_cleanup_signal;
retval = copy_namespaces(clone_flags, p);
if (retval)goto bad_fork_cleanup_mm;
retval = copy_io(clone_flags, p);
if (retval)goto bad_fork_cleanup_namespaces;
retval = copy_thread(clone_flags, args->stack, args->stack_size, p, args->tls);
if (retval)goto bad_fork_cleanup_io;
// 设置栈尾
stackleak_task_init(p);if (pid != &init_struct_pid) {// 分配pidpid = alloc_pid(p->nsproxy->pid_ns_for_children, args->set_tid,args->set_tid_size);if (IS_ERR(pid)) {retval = PTR_ERR(pid);goto bad_fork_cleanup_thread;}}...   

对进程的各项初始化/赋值工作,回到_do_fork:

// 将特定于设备或引导的数据添加到input_pool,并初始化input_pool
add_latent_entropy();if (IS_ERR(p))return PTR_ERR(p);...// 首次唤醒创建的任务。此函数将执行一些初始调度程序统计,对于每个新创建的上下文,都必须这样做,然后将任务在运行队列上,并将其唤醒
wake_up_new_task(p);// pid引用计数器减1put_pid(pid);return nr;
}

kernel_thread函数这里做了内核线程的甄别及创建,如线程不能同时分配新的用户空间和pid命名空间,并且与父进程在同一个命名空间(用户、time),共享父进程的信号、虚拟内存等等,有自己的内核栈。

linux kernel_thread执行过程相关推荐

  1. linux脚本执行过程中被挂起,Linux学习笔记(八)——脚本执行的过程控制

    一.脚本执行过程中的控制 之前的内容中,运行编写好的脚本时都是在命令行上直接确定运行的,并且运行的脚本是实时的,这并不是脚本唯一的运行方式,下面的内容是脚本的其他运行方式.例如在Linux系统中如何控 ...

  2. Linux命令执行过程中的配置文件信息

    命令执行过程 前面讲到过使用 alias 可以建立别名,比如创建了一个 ls 的别名,其实 ls 有少的指令,那么到底是哪一个会被选中执行呢?基本上,指令运行顺序可以这样看: 以相对.绝对路径执行命令 ...

  3. linux 跟踪程序执行过程,用pvtrace和Graphviz实现对linux下C程序的函数调用跟踪

    用pvtrace和Graphviz实现对linux下C程序的函数调用跟踪 用pvtrace和Graphviz实现对linux下C程序的函数调用跟踪 1:功能介绍,使用本方法可以实现linux下C应用程 ...

  4. Linux is执行程序命令,linux命令执行过程详解

    1.执行命令 输入命令后回车 提请shell程序找到键入命令所对应的可执行程序或者代码,并且由其分期后,提交给内核分配资源将其运行起来. 在shell中可执行的命令有俩类: 内部命令:由shell自带 ...

  5. LINUX内核分析第八周总结:进程的切换和系统的一般执行过程

    一.进程调度与进程切换 1.不同的进程有不同的调度需求 第一种分类: I/O密集型(I/O-bound) 频繁的进行I/O 通常会花费很多时间等待I/O操作的完成 CPU密集型(CPU-bound) ...

  6. 《Linux内核分析》 第八节 进程的切换和一般的执行过程

    张嘉琪 原创作品转载请注明出处 <Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000 Linux内核分析 第八 ...

  7. linux进程上下文切换的具体过程,Linux实验三 结合中断上下文切换和进程上下文切换分析Linux内核一般执行过程...

    fork系统调?创建?进程,也就?个进程变成了两个进程,两个进程执?相同的代码,只是fork系统调?在?进程和?进程中的返回值不同. 打开linux-5.4.34/arch/x86/entry/sys ...

  8. linux shell 执行多个文件,/etc/profile、~/.bash_profile等几个文件的执行过程

    关于登录linux时,/etc/profile.~/.bash_profile等几个文件的执行过程. 在登录Linux时要执行文件的过程如下: 在 刚登录Linux时,首先启动 /etc/profil ...

  9. Linux进程的分析和执行过程

    摘自:http://jingshengsun888.blog.51cto.com/1767811/1242215 一 分析 1 分析工具 strace -p 进程号 每一行都是一条系统调用,等号左边是 ...

最新文章

  1. 【windows】dos命令查看某个文件夹下所有文件目录列表
  2. centos7下安装intel Media Server Studio记录
  3. activiti实战系列 并行网关(parallelGateWay)
  4. 解决Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.7.0:compile
  5. 杨辉三角(下三角或者等腰三角)
  6. Linux hostname指令
  7. 2725. [Violet 6]故乡的梦(删边最短路同[TJOI2012]桥)
  8. Flask基础(03)--创建第一个Flask程序
  9. js创建file对象 字符串 txt_js-创建对象的多种方式
  10. 强化学习DQN算法实战之CartPole
  11. 贴片物料/电容/电阻的英制与公制封装
  12. 读研攻略(11)—十分钟学会简历撰写,两千字无废话
  13. (附源码)node.js宠物医生预约平台 毕业设计030945
  14. 电脑中如何打开进程管理器?
  15. 开发谷歌浏览器翻译插件
  16. Java Rasp技术浅析
  17. 轻快步伐远不足以跟上轻快心情
  18. Python语音基础操作--4.3共振峰估计
  19. pycharm中的红色小闪电
  20. 运行vue报错npm ERR! A complete log of this run can be found in解决办法

热门文章

  1. 一致性哈希的分析与实现
  2. JEECG 前端JS国际化实现,采用i18n新技术方案
  3. 【消息队列MQ】各类MQ比较
  4. 调试js 试用火狐的firebug
  5. 欢迎广大技术爱好者参与JEECG开源项目
  6. Python GUI
  7. 简单async/wait使用样例
  8. 【转】Elasticsearch5.0 安装问题集锦
  9. 关于jsp页面转换成excel格式下载遇到问题及解决
  10. java 校验护照_【示例教程】如何使用LEADTOOLS 的JAVA接口从护照中识别和提取数据...