本文共 8296 字,大约阅读时间需要 27 分钟。
arch_call_rest_init rest_init pid = kernel_thread(kernel_init, NULL, CLONE_FS); pid = kernel_thread(kthreadd, NULL, CLONE_FS | CLONE_FILES); cpu_startup_entry(CPUHP_ONLINE);
arm linux 内核源码剖析.pdf P407
start_kernel->rest_init->schedule_preempt_disabled -> schedule -> __schedule -> context_switch此函数执行后, kthreadd 开始运行
帮助 创建内核线程的人(该人调用kernel_create) 创建(kernel_thread)内核线程---------------------------------------------------1 2 3 为 kthreadd 进程的流程A B C 为 内核使用者 调用kernel_create的进程a b c 为 内核使用者 创建的进程1.idle 调用 kernel_thread 创建 kthreadd 进程 , 入口为 kthreadd 函数2.kthreadd 进程 循环检测 kthread_create_list,为空,睡眠A.我们(内核使用者) 调用 kernel_create 创建一个内核进程 xxx ,kernel_create 将 xxx 的信息(其中包括入口函数 mythread)填充到 kthread_create_list , 并 唤醒(wake_up) kthreadd 进程3.kthreadd 进程 苏醒,检查 kthread_create_list ,看到其中 有 xxx ,根据 xxx 获得 struct kthread_create_info *create , 并调用 create_kthread(create);4.create_kthread 调用 kernel_thread 创建 xxx 内核进程,入口为 kthread 函数B.我们调用 wake_up_process 来唤醒 xxx 内核进程a.xxx 内核进程 苏醒(被唤醒), 调用 create->threadfn/即mythread , mythread 开始执行其他kernel_create 创建的内核线程入口都是 kthreadkthread_create 创建的内核线程不会立刻运行.需要手工 wake up.kthread_create 创建的内核线程有可能不会执行相应线程函数threadfn而直接退出kthread_create 比 kernel_thread 更上层,不建议使用 kernel_thread---其他的创建线程的函数kthread_run 是 kthread_create 的封装kthread_create_on_node 和 kthread_create 类似
kernel_thread 的消费者 1. kernel_init kthreadd 的创建 2. kthread 的创建 3. call_usermodehelper_exec_work,用于 3.1.do_coredump 3.2.__orderly_reboot/__orderly_poweroff 3.3.kobject_uevent_env(mdev) 3.4.LKM的request_module------do_coredump 的消费者vector_swi local_restart: __sys_trace syscall_trace_enter secure_computing __secure_computing __seccomp_filter do_coredump ret_fast_syscall do_work_pending do_signal get_signal do_coredump
fs/lockd/svc.c:400: nlmsvc_task = kthread_create(lockd, nlmsvc_rqst, "%s", serv->sv_name);fs/io_uring.c:8208: sqd->thread = kthread_create(io_sq_thread, sqd,fs/io-wq.c:1107: wq->manager = kthread_create(io_wq_manager, wq, "io_wq_manager");kernel/irq/manage.c:1383: t = kthread_create(irq_thread, new, "irq/%d-%s", irq,kernel/irq/manage.c:1386: t = kthread_create(irq_thread, new, "irq/%d-s-%s", irq, request_threaded_irq request_nmi setup_percpu_irq request_percpu_irq request_percpu_nmi kernel/workqueue.c:4236: rescuer->task = kthread_create(rescuer_thread, rescuer, "%s", wq->name); 消费者(包括 events 内核线程workqueue_init_early->system_wq = alloc_workqueue("events", 0, 0);) alloc_workqueue init_rescuer kthread_create(rescuer_thread, rescuer, "%s", wq->name) list_add_tail_rcu(&wq->list, &workqueues); kernel_init kernel_init_freeable workqueue_init list_for_each_entry(wq, &workqueues, list) init_rescuer kthread_create(rescuer_thread, rescuer, "%s", wq->name)
// 驱动相关drivers/mmc/core/sdio_irq.c:234: kthread_run(sdio_irq_thread, host,drivers/media/common/videobuf2/videobuf2-core.c:2925: threadio->thread = kthread_run(vb2_thread, q, "vb2-%s", thread_name);drivers/char/hw_random/core.c:461: hwrng_fill = kthread_run(hwrng_fillfn, NULL, "hwrng");// 文件系统相关fs/jbd2/journal.c:280: t = kthread_run(kjournald2, journal, "jbd2/%s",fs/lockd/clntlock.c:220: task = kthread_run(reclaimer, host, "%s-reclaim", host->h_name);fs/lockd/svc.c:404: "lockd_up: kthread_run failed, error=%d\n", error);fs/ext4/super.c:3622: ext4_lazyinit_task = kthread_run(ext4_lazyinit_thread,fs/ext4/mmp.c:378: EXT4_SB(sb)->s_mmp_tsk = kthread_run(kmmpd, mmpd_data, "kmmpd-%.*s",kernel/time/clocksource.c:142: kthread_run(clocksource_watchdog_kthread, NULL, "kwatchdog"); 看门狗内核进程kernel/rcu/tasks.h:249: t = kthread_run(rcu_tasks_kthread, rtp, "%s_kthread", rtp->kname);内存管理相关的内核进程mm/oom_kill.c:680: oom_reaper_th = kthread_run(oom_reaper, NULL, "oom_reaper"); // oom_reaper 内核进程mm/page_alloc.c:2107: kthread_run(deferred_init_memmap, NODE_DATA(nid), "pgdatinit%d", nid);mm/compaction.c:2903: pgdat->kcompactd = kthread_run(kcompactd, pgdat, "kcompactd%d", nid);mm/vmscan.c:4052: pgdat->kswapd = kthread_run(kswapd, pgdat, "kswapd%d", nid);
net/sunrpc/svc.c:730: task = kthread_create_on_node(serv->sv_ops->svo_function, rqstp,fs/io-wq.c:690: worker->task = kthread_create_on_node(io_wqe_worker, worker, wqe->node,kernel/kthread.c:490: p = kthread_create_on_node(threadfn, data, cpu_to_node(cpu), namefmt, // 封装出了 kthread_create_on_cpu smpboot_register_percpu_thread // spawn_ksoftirqd -> smpboot_register_percpu_thread(&softirq_threads)kernel/workqueue.c:1935: worker->task = kthread_create_on_node(worker_thread, worker, pool->node, // 创建 kworker/xxx // workqueue_init -> create_worker -> kthread_create_on_node
// 进程 1 2 的 父进程为 0// 其他所有内核线程(被[]包括的) 父进程都是 kthreadd进程ID 所属用户 状态 COMMAND进程名 进程创建文件 进程创建函数// 1号用户进程 1 root 1412 S { linuxrc} init //init/main.c kernel_thread // 1号用户进程 // 2号内核进程 2 root 0 SW [kthreadd] // init/main.c kernel_thread // 2号内核线程,负责 创建所有的内核线程// 内核的管家进程 3 root 0 IW [kworker/0:0-eve] //kernel/workqueue.c create_worker 4 root 0 IW< [kworker/0:0H-kb] 5 root 0 IW [kworker/u2:0-ev] 16 root 0 IW [kworker/0:1-eve] 30 root 0 IW< [kworker/0:1H-kb] 31 root 0 IW< [kworker/u3:1-xp] 48 root 0 IW [kworker/u2:7-nf] 67 root 0 IW< [kworker/u3:4-xp] // "kworker" is a placeholder process for kernel worker threads, which perform most of the actual processing for the kernel, especially in cases where there are interrupts, timers, I/O, etc. // These typically correspond to the vast majority of any allocated "system" time to running processes. // It is not something that can be safely removed from the system in any way, and is completely unrelated to nepomuk or KDE (except in that these programs may make system calls, which may require the kernel to do something). // 用于执行内核工作队列,分为绑定 CPU (名称格式为 kworker/0:0-eve)和未绑定 CPU(名称格式为 kworker/u3:4-xp)两类。 7 root 0 SW [ksoftirqd/0] // kernel/softirq.c smpboot_register_percpu_thread // ksoftirqd以与kworker几乎相同的方式处理 softirq // softirq 使用的内核线程ksoftirqd// 模块相关进程 // 内存相关进程 6 root 0 IW< [mm_percpu_wq] // mm/vmstat.c alloc_workqueue 10 root 0 SW [oom_reaper] // mm/oom_kill.c kthread_run 11 root 0 IW< [writeback] // mm/backing-dev.c alloc_workqueue 12 root 0 SW [kcompactd0] // mm/compaction.c kthread_run 19 root 0 SW [kswapd0] // mm/vmscan.c kthread_run // 用于内存回收 // 网络相关进程 20 root 0 IW< [nfsiod] // fs/nfs/inode.c alloc_workqueue 21 root 0 IW< [ipv6_addrconf] // net/ipv6/addrconf.c create_workqueue 8 root 0 IW< [netns] // net/core/net_namespace.c create_singlethread_workqueue 9 root 0 IW< [inet_frag_wq] // net/ipv4/inet_fragment.c create_workqueue // 块设备相关进程 13 root 0 IW< [kblockd] // block/blk-core.c alloc_workqueue // rpc相关 15 root 0 IW< [rpciod] // net/sunrpc/sched.c alloc_workqueue 18 root 0 IW< [xprtiod] // net/sunrpc/sched.c alloc_workqueue // 防死机看门狗内核进程 14 root 0 SW [watchdogd] // drivers/watchdog/watchdog_dev.c kthread_create_worker // mmc 相关 23 root 0 IW< [sdhci] // drivers/mmc/host/sdhci.c alloc_workqueue 24 root 0 SW [irq/88-mmc0] // drivers/mmc/host/sdhci.c request_threaded_irq // 给中断线程化使用的irq内核线程 29 root 0 IW< [mmc_complete] // drivers/mmc/core/block.c alloc_workqueue// 用户进程 53 root 4100 S /sbin/mdev -df 64 root 19388 S /usr/bin/Xorg :0.0 vt01 -s 0 -noreset -allowMouseOpe// 后期 需 重点关注 这些进程// init kthreadd // kworker ksoftirqd // mem(5个) kblockd mmc(3个) watchdogd 问题 :workqueue_init_early -> system_wq = alloc_workqueue("events", 0, 0); 创建的 events 进程哪里去了???
migration:在负载均衡过程中,把进程迁移到 CPU 上。每个 CPU 都有一个 migration 内核线程。 jbd2/sda1-8:jbd 是 Journaling Block Device 的缩写,用来为文件系统提供日志功能,以保证数据的完整性;名称中的 sda1-8,表示磁盘分区名称和设备号。每个使用了 ext4 文件系统的磁盘分区,都会有一个 jbd2 内核线程。 pdflush:用于将内存中的脏页(被修改过,但还未写入磁盘的文件页)写入磁盘(已经在 3.10 中合并入了 kworker 中)。
转载地址:http://jcigi.baihongyu.com/