1、probe 是进程里面跑的吗?
2、probe 可以睡眠吗?睡眠后怎么被再次唤醒并继续执行?
3、probe 调度和执行顺序
4、probe 没跑完 系统怎处理
probe 是驱动用的探测函数,明白一点 探测的目的。驱动的加载是需要条件的,问了保证系统的精简 ,probe作为一个判断条件,通过检查对应设备是否存在当前硬件系统中,通常是如果存在 就允许加载驱动,当然也有例外,就是有些模块存在但是探测不到,所以会在让probe函数 探测成功。
我们来看下 通常一个driver驱动会通过subsys_initcall 或者module_init 方式加载。
我们来看下这两个函数的关系。
#define module_init(x) __initcall(x);
#define __initcall(fn) device_initcall(fn)
#define pure_initcall(fn) __define_initcall(fn, 0)
#define core_initcall(fn) __define_initcall(fn, 1)
#define core_initcall_sync(fn) __define_initcall(fn, 1s)
#define postcore_initcall(fn) __define_initcall(fn, 2)
#define postcore_initcall_sync(fn) __define_initcall(fn, 2s)
#define arch_initcall(fn) __define_initcall(fn, 3)
#define arch_initcall_sync(fn) __define_initcall(fn, 3s)
#define subsys_initcall(fn) __define_initcall(fn, 4)
#define subsys_initcall_sync(fn) __define_initcall(fn, 4s)
#define fs_initcall(fn) __define_initcall(fn, 5)
#define fs_initcall_sync(fn) __define_initcall(fn, 5s)
#define rootfs_initcall(fn) __define_initcall(fn, rootfs)
#define device_initcall(fn) __define_initcall(fn, 6)
#define device_initcall_sync(fn) __define_initcall(fn, 6s)
#define late_initcall(fn) __define_initcall(fn, 7)
#define late_initcall_sync(fn) __define_initcall(fn, 7s)
#define __define_initcall(fn, id) ___define_initcall(fn, id, .initcall##id)
#define ___define_initcall(fn, id, __sec) \
__ADDRESSABLE(fn) \
asm(".section \"" #__sec ".init\", \"a\" \n" \ //.section ".initcall6.init","a"
"__initcall_" #fn #id ": \n" \ // __initcall_ "函数" "6" :
".long " #fn " - . \n" \ //.long "函数" -.
".previous \n"); //.previous
#define INIT_CALLS_LEVEL(level) \
__initcall##level##_start = .; \
KEEP(*(.initcall##level##.init)) \ //.initcall6.init
KEEP(*(.initcall##level##s.init)) \
#define INIT_CALLS \
__initcall_start = .; \
KEEP(*(.initcallearly.init)) \
INIT_CALLS_LEVEL(0) \
INIT_CALLS_LEVEL(1) \
INIT_CALLS_LEVEL(2) \
INIT_CALLS_LEVEL(3) \
INIT_CALLS_LEVEL(4) \
INIT_CALLS_LEVEL(5) \
INIT_CALLS_LEVEL(rootfs) \
INIT_CALLS_LEVEL(6) \
INIT_CALLS_LEVEL(7) \
__initcall_end = .;
我们来看下整个如下这log
[ 0.000000] <0>-(0)[0:swapper]Booting Linux on physical CPU 0x0000000000 [0x410fd034]
[ 0.000000] <0>-(0)[0:swapper]Linux version 4.19.127 (nobody@android-build) (Android (6443078 based on r383902) clang version 11.0.1 (https://android.googlesource.com/toolchain/llvm-project b397f81060ce6d701042b782172ed13bee898b79), LLD 11.0.1 (/buildbot/tmp/tmp6_m7QH b397f81060ce6d701042b782172ed13bee898b79)) #2 SMP PREEMPT Wed Apr 7 09:27:22 CST 2021
[ 0.000000] <0>-(0)[0:swapper]Machine model: xxxx
[ 0.000000] <0>-(0)[0:swapper]OF: reserved mem: initialized node reserve-memory-sspm_share, compatible id mediatek,reserve-memory-sspm_share
[ 0.000000] <0>-(0)[0:swapper]Reserved memory: created CMA memory pool at 0x000000012f000000, size 256 MiB
[ 0.000000] <0>-(0)[0:swapper]OF: reserved mem: initialized node ssmr-reserved-cma_memory, compatible id shared-dma-pool
[ 0.000000] <0>-(0)[0:swapper]Reserved memory: created DMA memory pool at 0x00000000be000000, size 3 MiB
[ 0.000000] <0>-(0)[0:swapper]OF: reserved mem: initialized node wifi-reserve-memory, compatible id shared-dma-pool
[ 0.000000] <0>-(0)[0:swapper]ion_reserve_memory_to_camera: name:ion-carveout-heap,base:cfffb000,size:0x5000
[ 0.000000] <0>-(0)[0:swapper]OF: reserved mem: initialized node ion-carveout-heap, compatible id mediatek,ion-carveout-heap
[ 0.000000] <0>-(0)[0:swapper][memblock]mediatek,minirdump: 0x47d70000 - 0x47d80000 (0x10000)
[ 0.000000] <0>-(0)[0:swapper]OF: reserved mem: initialized node mblock-11-minirdump, compatible id mediatek,minirdump
[ 0.000000] <0>-(0)[0:swapper]cma: Reserved 16 MiB at 0x00000000ff000000
[ 0.000000] <0>-(0)[0:swapper]psci: probing for conduit method from DT.
[ 0.000000] <0>-(0)[0:swapper]psci: PSCIv1.0 detected in firmware.
[ 0.000000] <0>-(0)[0:swapper]psci: Using standard PSCI v0.2 function IDs
[ 0.000000] <0>-(0)[0:swapper]psci: MIGRATE_INFO_TYPE not supported.
[ 0.000000] <0>-(0)[0:swapper]psci: SMC Calling Convention v1.0
[ 0.000000] <0>-(0)[0:swapper]percpu: Embedded 24 pages/cpu s58776 r8192 d31336 u98304
[ 0.000000] <0>-(0)[0:swapper]Detected VIPT I-cache on CPU0
[ 15.766233] <7>.(7)[1:init]init 25: [15720][0]starting service 'vendor.audio-hal'...
[ 15.771998] <3>.(3)[1:init]init 25: [15720][0]starting service 'bluetooth-1-0'...
[ 15.778482] <1>.(1)[1:init]init 25: [15720][0]starting service 'vendor.cas-hal-1-2'...
[ 15.784456] <1>.(1)[1:init]init 25: [15720][0]starting service 'vendor.drm-clearkey-hal-1-3'...
[ 15.790797] <2>.(2)[1:init]init 25: [15720][0]starting service 'vendor.drm-widevine-hal-1-3'...
[ 15.796519] <2>.(2)[331:init]init 22: [15765][0]ReapLogC PropSet [init.svc_debug_pid.hidl_memory]=[477]15734
进程0和进程1 0:swapper和 1:init
所有进程的祖先叫做进程0,idle进程或者swapper进程,它是在Linux的初始化阶段从无到有的创建的内核进程(该进程描述符使用的是静态分配的数据结构,其他进程都是动态分配的)。
进程0调用start_kernel()函数初始化内核需要的所有数据结构,激活中断,创建一个进程1 的内核进程(init进程),进程0和进程1 共享每进程的所有内核数据结构。
多处理器中,每个CPU都有自己的进程0。
进程0创建的内核进程执行init()函数初始化内核。然后调用execve()系统调用装入可执行程序init.至此,init为一个普通的进程,且拥有每进程内核数据结构。在系统关闭之前,init一直存在,它创建和监控在操作系统外层的执行的所有进程的活动。
这样*进程调度算法*总能成功的选择要执行的进程。总是至少有一个进程。即swapper进程。PID等于0。只有当没有其他进程处于TASK_RUNNING状态下,调度程序才选择进程0。
我们总结下和probe相关的问题的信息。
前期 swapper 作为系统初始化的 进程载体, 运行会probe 函数, 自然可以创建线程 , 不过一般probe可能比较晚一点,前面先把平台环境配置,后面再探测一些设备,这个时候即使创建也基本不影响swapper 的工作了。 probe 也是系统定义顺序分类执行的,对于同一级别的probe ,我猜想估计要看 编译器 排的init字段的顺序了。
我们做个实验 再swapper 睡眠几秒 看下是不是 系统再一直等待了。
[ 2.330419] <3>.(3)[1:swapper/0]usb-hdrc: version 6.0, ?dma?, otg (peripheral+host)
[ 2.344275] <5>-(5)[0:swapper/5]Perf order domain is not ready!
[ 2.361239] <3>-(3)[1:swapper/0]Perf order domain is not ready!
[ 2.378208] <1>-(1)[0:swapper/1]Perf order domain is not ready!
[ 2.395181] <7>-(7)[0:swapper/7]Perf order domain is not ready!
[ 3.023018] <5>-(5)[0:swapper/5]Perf order domain is not ready!
[ 3.039985] <3>-(3)[1:swapper/0]Perf order domain is not ready!
[ 3.056954] <1>-(1)[0:swapper/1]Perf order domain is not ready!
[ 3.073925] <7>-(7)[0:swapper/7]Perf order domain is not ready!
[ 3.090894] <5>-(5)[0:swapper/5]Perf order domain is not ready!
[ 4.346573] <1>-(1)[0:swapper/1]Perf order domain is not ready!
[ 4.363544] <7>-(7)[0:swapper/7]Perf order domain is not ready!
[ 4.380512] <5>-(5)[0:swapper/5]Perf order domain is not ready!
[ 4.391988] <3>.(3)[1:swapper/0]usb_probe mac=0xffffff800baf0000, phy=0xffffff800bb10000, irq=243
我因我这是多核cpu 出现 swapper其他核心的 打印 但是 再swapper/0 上是再等待,不过至少说明了 ,在前期没有其他任务的时候系统,cpu0 的确 再空跑灯定时器唤醒。
大部分格式都是 kworker /u2:0 或者 kworker /0:0H, 查看资料得知:
内核中有很多kworker,有绑定cpu的和不绑定cpu的,它支持cpu的hotplug时work的迁移。
u:是unbound的缩写,代表没有绑定特定的CPU,kworker /u2:0中的 2 是 work_pool 的ID。