本教程操作环境:linux5.9.8系统、Dell G3电脑。

linux内核有main函数吗?

linux内核源码之main函数解析


(资料图片仅供参考)

这几天一直在纠结:

main函数是程序的入口,一个程序启动后,经过bootloader的初始化就该经main函数进入C语言的世界,但是linux中每个应用程序的开始都是从main函数开始的。linux下有多个应用程序,岂不是有很多个main。那bootloader会知道跳到哪个main?多个main编译怎么不冲突?

在网上搜索了很久,渐渐的有些明白了:

1、main函数是C语言的入口,这句话没错;但是这句话仅仅是一个约定,而非一个亘古不变的铁律!从程序的更为本质的汇编代码来看,只是大家约定汇编初始化完了后,跳到一个名字叫"main"的标号处;言外之意就是这个标号也是可以改名的,比如linux的C语言入口就是start_kernel();从这个标号地址后就是C语言的天下了。用main这个名字仅仅是因为大家的约定而已,不遵守约定能玩的转也行啊,就像苹果充电线啥的都和别人不一样。

2、在编译时是不存多个main函数的!每个应用程序虽说都有一个main函数(从应用程序来看应用程序的入口是main函数哦);但是应用程序都是独立编译的,不会一起编译,操作系统内核就更不可能和应用程序一起编译了!所以根本不存在多个main冲突的!!可能是统一操作系统与应用程序之间的接口,亦或是侧面影响下main是程序入口的说法,main是应用程序和操作系统之间约定好的一个接口名!所以linux中每个应用程序的第一个函数必须是main。除非你改掉了内核调度的接口地方。

3、linux的应用程序的安装启动也可以类比下我们每天都在用的Windows。Windows应用程序的安装其实也是把一些执行文件拷贝到指定的文件夹里(从绿色软件看),点击就可以运行。linux下也是这样。编译好的bin文件放到指定的文件夹目录下,然后用命令启动执行。

/* *  linux/init/main.c * *  Copyright (C) 1991, 1992  Linus Torvalds * *  GK 2/5/95  -  Changed to support mounting root fs via NFS *  Added initrd & change_root: Werner Almesberger & Hans Lermen, Feb "96 *  Moan early if gcc is old, avoiding bogus kernels - Paul Gortmaker, May "96 *  Simplified starting of init:  Michael A. Griffith <grif@acm.org>  * start_kernel->rest_init->kernel_init创建用户init  pid=1                          ->kthreadd管理内核线程     pid=x                          ->pid=0,是idle线程    在rest_init中,会创建kernel_init线程,它负责创建用户init进程,完成工作后,自己    化身为idle线程 */ #include <linux/types.h>#include <linux/module.h>#include <linux/proc_fs.h>#include <linux/kernel.h>#include <linux/syscalls.h>#include <linux/stackprotector.h>#include <linux/string.h>#include <linux/ctype.h>#include <linux/delay.h>#include <linux/ioport.h>#include <linux/init.h>#include <linux/initrd.h>#include <linux/bootmem.h>#include <linux/acpi.h>#include <linux/tty.h>#include <linux/percpu.h>#include <linux/kmod.h>#include <linux/vmalloc.h>#include <linux/kernel_stat.h>#include <linux/start_kernel.h>#include <linux/security.h>#include <linux/smp.h>#include <linux/profile.h>#include <linux/rcupdate.h>#include <linux/moduleparam.h>#include <linux/kallsyms.h>#include <linux/writeback.h>#include <linux/cpu.h>#include <linux/cpuset.h>#include <linux/cgroup.h>#include <linux/efi.h>#include <linux/tick.h>#include <linux/interrupt.h>#include <linux/taskstats_kern.h>#include <linux/delayacct.h>#include <linux/unistd.h>#include <linux/rmap.h>#include <linux/mempolicy.h>#include <linux/key.h>#include <linux/buffer_head.h>#include <linux/page_cgroup.h>#include <linux/debug_locks.h>#include <linux/debugobjects.h>#include <linux/lockdep.h>#include <linux/kmemleak.h>#include <linux/pid_namespace.h>#include <linux/device.h>#include <linux/kthread.h>#include <linux/sched.h>#include <linux/signal.h>#include <linux/idr.h>#include <linux/kgdb.h>#include <linux/ftrace.h>#include <linux/async.h>#include <linux/kmemcheck.h>#include <linux/sfi.h>#include <linux/shmem_fs.h>#include <linux/slab.h>#include <linux/perf_event.h> #include <asm/io.h>#include <asm/bugs.h>#include <asm/setup.h>#include <asm/sections.h>#include <asm/cacheflush.h> #ifdef CONFIG_X86_LOCAL_APIC#include <asm/smp.h>#endif static int kernel_init(void *); extern void init_IRQ(void);extern void fork_init(unsigned long);extern void mca_init(void);extern void sbus_init(void);extern void prio_tree_init(void);extern void radix_tree_init(void);#ifndef CONFIG_DEBUG_RODATAstatic inline void mark_rodata_ro(void) { }#endif #ifdef CONFIG_TCextern void tc_init(void);#endif /* * Debug helper: via this flag we know that we are in "early bootup code" * where only the boot processor is running with IRQ disabled.  This means * two things - IRQ must not be enabled before the flag is cleared and some * operations which are not allowed with IRQ disabled are allowed while the * flag is set. */bool early_boot_irqs_disabled __read_mostly; enum system_states system_state __read_mostly;EXPORT_SYMBOL(system_state); /* * Boot command-line arguments */#define MAX_INIT_ARGS CONFIG_INIT_ENV_ARG_LIMIT#define MAX_INIT_ENVS CONFIG_INIT_ENV_ARG_LIMIT extern void time_init(void);/* Default late time init is NULL. archs can override this later. */void (*__initdata late_time_init)(void);extern void softirq_init(void); /* Untouched command line saved by arch-specific code. */char __initdata boot_command_line[COMMAND_LINE_SIZE];/* Untouched saved command line (eg. for /proc) */char *saved_command_line;/* Command line for parameter parsing */static char *static_command_line; static char *execute_command;static char *ramdisk_execute_command; /* * If set, this is an indication to the drivers that reset the underlying * device before going ahead with the initialization otherwise driver might * rely on the BIOS and skip the reset operation. * * This is useful if kernel is booting in an unreliable environment. * For ex. kdump situaiton where previous kernel has crashed, BIOS has been * skipped and devices will be in unknown state. */unsigned int reset_devices;EXPORT_SYMBOL(reset_devices); static int __init set_reset_devices(char *str){    reset_devices = 1;    return 1;} __setup("reset_devices", set_reset_devices); static const char * argv_init[MAX_INIT_ARGS+2] = { "init", NULL, };const char * envp_init[MAX_INIT_ENVS+2] = { "HOME=/", "TERM=linux", NULL, };static const char *panic_later, *panic_param; extern const struct obs_kernel_param __setup_start[], __setup_end[]; static int __init obsolete_checksetup(char *line){    const struct obs_kernel_param *p;    int had_early_param = 0;     p = __setup_start;    do {        int n = strlen(p->str);        if (parameqn(line, p->str, n)) {            if (p->early) {                /* Already done in parse_early_param?                 * (Needs exact match on param part).                 * Keep iterating, as we can have early                 * params and __setups of same names 8( */                if (line[n] == "\0" || line[n] == "=")                    had_early_param = 1;            } else if (!p->setup_func) {                printk(KERN_WARNING "Parameter %s is obsolete,"                       " ignored\n", p->str);                return 1;            } else if (p->setup_func(line + n))                return 1;        }        p++;    } while (p < __setup_end);     return had_early_param;} /* * This should be approx 2 Bo*oMips to start (note initial shift), and will * still work even if initially too large, it will just take slightly longer */unsigned long loops_per_jiffy = (1<<12);EXPORT_SYMBOL(loops_per_jiffy);static int __init debug_kernel(char *str){    console_loglevel = 10;    return 0;}static int __init quiet_kernel(char *str){    console_loglevel = 4;    return 0;}early_param("debug", debug_kernel);early_param("quiet", quiet_kernel);static int __init loglevel(char *str){    int newlevel;    /*     * Only update loglevel value when a correct setting was passed,     * to prevent blind crashes (when loglevel being set to 0) that     * are quite hard to debug     */    if (get_option(&str, &newlevel)) {        console_loglevel = newlevel;        return 0;    }    return -EINVAL;}early_param("loglevel", loglevel);/* Change NUL term back to "=", to make "param" the whole string. */static int __init repair_env_string(char *param, char *val){    if (val) {        /* param=val or param="val"? */        if (val == param+strlen(param)+1)            val[-1] = "=";        else if (val == param+strlen(param)+2) {            val[-2] = "=";            memmove(val-1, val, strlen(val)+1);            val--;        } else            BUG();    }    return 0;}/* * Unknown boot options get handed to init, unless they look like * unused parameters (modprobe will find them in /proc/cmdline). */static int __init unknown_bootoption(char *param, char *val){    repair_env_string(param, val);    /* Handle obsolete-style parameters */    if (obsolete_checksetup(param))        return 0;    /* Unused module parameter. */    if (strchr(param, ".") && (!val || strchr(param, ".") < val))        return 0;    if (panic_later)        return 0;    if (val) {        /* Environment option */        unsigned int i;        for (i = 0; envp_init[i]; i++) {            if (i == MAX_INIT_ENVS) {                panic_later = "Too many boot env vars at `%s"";                panic_param = param;            }            if (!strncmp(param, envp_init[i], val - param))                break;        }        envp_init[i] = param;    } else {        /* Command line option */        unsigned int i;        for (i = 0; argv_init[i]; i++) {            if (i == MAX_INIT_ARGS) {                panic_later = "Too many boot init vars at `%s"";                panic_param = param;            }        }        argv_init[i] = param;    }    return 0;}static int __init init_setup(char *str){    unsigned int i;    execute_command = str;    /*     * In case LILO is going to boot us with default command line,     * it prepends "auto" before the whole cmdline which makes     * the shell think it should execute a script with such name.     * So we ignore all arguments entered _before_ init=... [MJ]     */    for (i = 1; i < MAX_INIT_ARGS; i++)        argv_init[i] = NULL;    return 1;}__setup("init=", init_setup);static int __init rdinit_setup(char *str){    unsigned int i;    ramdisk_execute_command = str;    /* See "auto" comment in init_setup */    for (i = 1; i < MAX_INIT_ARGS; i++)        argv_init[i] = NULL;    return 1;}__setup("rdinit=", rdinit_setup);#ifndef CONFIG_SMPstatic const unsigned int setup_max_cpus = NR_CPUS;#ifdef CONFIG_X86_LOCAL_APICstatic void __init smp_init(void){    APIC_init_uniprocessor();}#else#define smp_init()  do { } while (0)#endifstatic inline void setup_nr_cpu_ids(void) { }static inline void smp_prepare_cpus(unsigned int maxcpus) { }#endif/* * We need to store the untouched command line for future reference. * We also need to store the touched command line since the parameter * parsing is performed in place, and we should allow a component to * store reference of name/value for future reference. */static void __init setup_command_line(char *command_line){    saved_command_line = alloc_bootmem(strlen (boot_command_line)+1);    static_command_line = alloc_bootmem(strlen (command_line)+1);    strcpy (saved_command_line, boot_command_line);    strcpy (static_command_line, command_line);}/* * We need to finalize in a non-__init function or else race conditions * between the root thread and the init thread may cause start_kernel to * be reaped by free_initmem before the root thread has proceeded to * cpu_idle. * * gcc-3.4 accidentally inlines this function, so use noinline. */static __initdata DECLARE_COMPLETION(kthreadd_done);static noinline void __init_refok rest_init(void){    int pid;    rcu_scheduler_starting();//READ-COPY UPDATE启动    /*     * We need to spawn init first so that it obtains pid 1, however     * the init task will end up wanting to create kthreads, which, if     * we schedule it before we create kthreadd, will OOPS.     * 创建一个内核线程,它的线程函数是kernel_init,pid=1,内核进程     */    kernel_thread(kernel_init, NULL, CLONE_FS | CLONE_SIGHAND);    //numa策略设置    numa_default_policy();    //全局链表kthread_create_list中的kthread内核线程都被运行    //kthreadd线程管理和调度其它内核线程    pid = kernel_thread(kthreadd, NULL, CLONE_FS | CLONE_FILES);    rcu_read_lock();    //通过pid,ini_pid_ns取得kthreadd地址    kthreadd_task = find_task_by_pid_ns(pid, &init_pid_ns);    rcu_read_unlock();    //通知在kthreadd_done条件的kernel_init线程    complete(&kthreadd_done);    /*     * The boot idle thread must execute schedule()     * at least once to get things moving:     * idle 线程初始化     */    init_idle_bootup_task(current);    //抢占禁用    schedule_preempt_disabled();    /* Call into cpu_idle with preempt disabled */    cpu_idle();}/* Check for early params. */static int __init do_early_param(char *param, char *val){    const struct obs_kernel_param *p;    for (p = __setup_start; p < __setup_end; p++) {        if ((p->early && parameq(param, p->str)) ||            (strcmp(param, "console") == 0 &&             strcmp(p->str, "earlycon") == 0)        ) {            if (p->setup_func(val) != 0)                printk(KERN_WARNING                       "Malformed early option "%s"\n", param);        }    }    /* We accept everything at this stage. */    return 0;}void __init parse_early_options(char *cmdline){    parse_args("early options", cmdline, NULL, 0, 0, 0, do_early_param);}/* Arch code calls this early on, or if not, just before other parsing. */void __init parse_early_param(void){    static __initdata int done = 0;    static __initdata char tmp_cmdline[COMMAND_LINE_SIZE];    if (done)        return;    /* All fall through to do_early_param. */    strlcpy(tmp_cmdline, boot_command_line, COMMAND_LINE_SIZE);    parse_early_options(tmp_cmdline);    done = 1;}/* *  Activate the first processor. */static void __init boot_cpu_init(void){    int cpu = smp_processor_id();    /* Mark the boot cpu "present", "online" etc for SMP and UP case */    set_cpu_online(cpu, true);    set_cpu_active(cpu, true);    set_cpu_present(cpu, true);    set_cpu_possible(cpu, true);}void __init __weak smp_setup_processor_id(void){}void __init __weak thread_info_cache_init(void){}/* * Set up kernel memory allocators */static void __init mm_init(void){    /*     * page_cgroup requires contiguous pages,     * bigger than MAX_ORDER unless SPARSEMEM.     */    page_cgroup_init_flatmem();    mem_init();    kmem_cache_init();    percpu_init_late();    pgtable_cache_init();    vmalloc_init();}asmlinkage void __init start_kernel(void){    char * command_line;    extern const struct kernel_param __start___param[], __stop___param[];    /*     * Need to run as early as possible, to initialize the     * lockdep hash:     */    //初始化2个hash表-Lock Dependency Validator(内核依赖的关系表)    lockdep_init();    smp_setup_processor_id(); //空函数    debug_objects_early_init();//初始化内核调试相关    /*     * Set up the the initial canary ASAP:     */    boot_init_stack_canary();//栈溢出保护初始化    //控制组初始化-cgroup-资源任务分组管理    cgroup_init_early();    local_irq_disable();//关中断    early_boot_irqs_disabled = true;/* * Interrupts are still disabled. Do necessary setups, then * enable them */    tick_init();//时钟初始化    boot_cpu_init();//启动cpu初始化    page_address_init();//页面初始化    printk(KERN_NOTICE "%s", linux_banner);    setup_arch(&command_line);//架构相关初始化    mm_init_owner(&init_mm, &init_task);//内存管理初始化    mm_init_cpumask(&init_mm);//内存管理初始化    setup_command_line(command_line);//处理命令行(保存2份)    setup_nr_cpu_ids();//cpuid相关    setup_per_cpu_areas();//每cpu变量申请空间(包括gdt)    //smp中用来启动的cpu    smp_prepare_boot_cpu(); /* arch-specific boot-cpu hooks */     //建立系统内存页区链表    build_all_zonelists(NULL);    //内存页相关初始化    page_alloc_init();    printk(KERN_NOTICE "Kernel command line: %s\n", boot_command_line);    //命令行boot_command_line    parse_early_param();    //解析参数    parse_args("Booting kernel", static_command_line, __start___param,           __stop___param - __start___param,           -1, -1, &unknown_bootoption);    //    jump_label_init();    /*     * These use large bootmem allocations and must precede     * kmem_cache_init()     * 内存初始化相关     */    setup_log_buf(0);    pidhash_init();    vfs_caches_init_early();    sort_main_extable();    trap_init();    mm_init();    /*     * Set up the scheduler prior starting any interrupts (such as the     * timer interrupt). Full topology setup happens at smp_init()     * time - but meanwhile we still have a functioning scheduler.     * 调度初始化     */    sched_init();    /*     * Disable preemption - early bootup scheduling is extremely     * fragile until we cpu_idle() for the first time.     * 抢占禁用     */    preempt_disable();    if (!irqs_disabled()) {        printk(KERN_WARNING "start_kernel(): bug: interrupts were "                "enabled *very* early, fixing it\n");        local_irq_disable();    }    idr_init_cache();//idr    perf_event_init();//performance event    rcu_init();//read-copy-update 机制    radix_tree_init();//radix树机制    /* init some links before init_ISA_irqs() */    early_irq_init();//中断请求    init_IRQ();//中断请求    prio_tree_init();//优先查找树    init_timers();//时钟    hrtimers_init();//High-resolution kernel timers高精度内核时钟    softirq_init();//软中断    timekeeping_init();//时间相关    time_init();//时间    profile_init();//分配内核性能统计保存的内存    call_function_init();//smp中每cpu的call_single_queue初始化    if (!irqs_disabled())        printk(KERN_CRIT "start_kernel(): bug: interrupts were "                 "enabled early\n");    early_boot_irqs_disabled = false;//中断请求开    local_irq_enable();//本地中断开    kmem_cache_init_late();//kmem后期初始化    /*     * HACK ALERT! This is early. We"re enabling the console before     * we"ve done PCI setups etc, and console_init() must be aware of     * this. But we do want output early, in case something goes wrong.     */    console_init();//初始化系统控制台结构    if (panic_later)        panic(panic_later, panic_param);    //锁依赖信息    lockdep_info();    /*     * Need to run this when irqs are enabled, because it wants     * to self-test [hard/soft]-irqs on/off lock inversion bugs     * too:     */    locking_selftest();#ifdef CONFIG_BLK_DEV_INITRD    if (initrd_start && !initrd_below_start_ok &&        page_to_pfn(virt_to_page((void *)initrd_start)) < min_low_pfn) {        printk(KERN_CRIT "initrd overwritten (0x%08lx < 0x%08lx) - "            "disabling it.\n",            page_to_pfn(virt_to_page((void *)initrd_start)),            min_low_pfn);        initrd_start = 0;    }#endif    page_cgroup_init();//control groups初始化    debug_objects_mem_init();//对象调试    kmemleak_init();//检测内核内存泄漏的功能    setup_per_cpu_pageset();//申请并初始化每cpu页set    numa_policy_init();//numa相关    if (late_time_init)        late_time_init();    //初始化每cpusched_clock_data=ktime_now    sched_clock_init();    calibrate_delay();//计算cpuMIPS百万条指令/s    pidmap_init();//pid进程id表初始化    anon_vma_init();//虚拟地址#ifdef CONFIG_X86    if (efi_enabled)//efi bois        efi_enter_virtual_mode();#endif    thread_info_cache_init();//申请thread_info的内存    cred_init();//credential健在分配     //根据物理内存大小,计算可创建进/线程数量    fork_init(totalram_pages);     proc_caches_init();//进程内存初始化    buffer_init();//页高速缓存    key_init();//红黑树内存,存keys    security_init();//安全相关    dbg_late_init();//调试相关    vfs_caches_init(totalram_pages);//虚拟文件系统初始化    signals_init();//sigqueue申请内存,信号系统    /* rootfs populating might need page-writeback */    page_writeback_init();//页回写#ifdef CONFIG_PROC_FS    proc_root_init();//proc文件系统初始化#endif    cgroup_init();//cgroup相关    cpuset_init();//cpuset相关    taskstats_init_early();//进程计数器    delayacct_init();//进程延时审计    check_bugs();//系统bug相关测试    //acpi总线    acpi_early_init(); /* before LAPIC and SMP init */    sfi_init_late();//Simple Firmware Interface    //功能追踪初始化,一种调试工具    ftrace_init();    /* Do the rest non-__init"ed, we"re now alive */    rest_init();}/* Call all constructor functions linked into the kernel. */static void __init do_ctors(void){#ifdef CONFIG_CONSTRUCTORS    ctor_fn_t *fn = (ctor_fn_t *) __ctors_start;    for (; fn < (ctor_fn_t *) __ctors_end; fn++)        (*fn)();#endif}bool initcall_debug;core_param(initcall_debug, initcall_debug, bool, 0644);static char msgbuf[64];static int __init_or_module do_one_initcall_debug(initcall_t fn){    ktime_t calltime, delta, rettime;    unsigned long long duration;    int ret;    printk(KERN_DEBUG "calling  %pF @ %i\n", fn, task_pid_nr(current));    calltime = ktime_get();    ret = fn();    rettime = ktime_get();    delta = ktime_sub(rettime, calltime);    duration = (unsigned long long) ktime_to_ns(delta) >> 10;    printk(KERN_DEBUG "initcall %pF returned %d after %lld usecs\n", fn,        ret, duration);    return ret;}int __init_or_module do_one_initcall(initcall_t fn){    int count = preempt_count();    int ret;    if (initcall_debug)        ret = do_one_initcall_debug(fn);    else        ret = fn();    msgbuf[0] = 0;    if (ret && ret != -ENODEV && initcall_debug)        sprintf(msgbuf, "error code %d ", ret);    if (preempt_count() != count) {        strlcat(msgbuf, "preemption imbalance ", sizeof(msgbuf));        preempt_count() = count;    }    if (irqs_disabled()) {        strlcat(msgbuf, "disabled interrupts ", sizeof(msgbuf));        local_irq_enable();    }    if (msgbuf[0]) {        printk("initcall %pF returned with %s\n", fn, msgbuf);    }    return ret;}extern initcall_t __initcall_start[];extern initcall_t __initcall0_start[];extern initcall_t __initcall1_start[];extern initcall_t __initcall2_start[];extern initcall_t __initcall3_start[];extern initcall_t __initcall4_start[];extern initcall_t __initcall5_start[];extern initcall_t __initcall6_start[];extern initcall_t __initcall7_start[];extern initcall_t __initcall_end[];static initcall_t *initcall_levels[] __initdata = {    __initcall0_start,    __initcall1_start,    __initcall2_start,    __initcall3_start,    __initcall4_start,    __initcall5_start,    __initcall6_start,    __initcall7_start,    __initcall_end,};static char *initcall_level_names[] __initdata = {    "early parameters",    "core parameters",    "postcore parameters",    "arch parameters",    "subsys parameters",    "fs parameters",    "device parameters",    "late parameters",};static void __init do_initcall_level(int level){    extern const struct kernel_param __start___param[], __stop___param[];    initcall_t *fn;    strcpy(static_command_line, saved_command_line);    parse_args(initcall_level_names[level],           static_command_line, __start___param,           __stop___param - __start___param,           level, level,           repair_env_string);    for (fn = initcall_levels[level]; fn < initcall_levels[level+1]; fn++)        do_one_initcall(*fn);}static void __init do_initcalls(void){    int level;    for (level = 0; level < ARRAY_SIZE(initcall_levels) - 1; level++)        do_initcall_level(level);}/* * Ok, the machine is now initialized. None of the devices * have been touched yet, but the CPU subsystem is up and * running, and memory and process management works. * * Now we can finally start doing some real work.. */static void __init do_basic_setup(void){    cpuset_init_smp();//smp cpuset相关    usermodehelper_init();//khelper单线程工作队列    shmem_init();//sheme机制    driver_init();//驱动各子系统    init_irq_proc();//proc中创建irq目录    do_ctors();//内核中所有构造函数,介于.ctors段中的函数    usermodehelper_enable();    //所有编译进内核的驱动模块初始化函数    do_initcalls();}static void __init do_pre_smp_initcalls(void){    initcall_t *fn;    for (fn = __initcall_start; fn < __initcall0_start; fn++)        do_one_initcall(*fn);}static void run_init_process(const char *init_filename){    argv_init[0] = init_filename;    kernel_execve(init_filename, argv_init, envp_init);}/* This is a non __init function. Force it to be noinline otherwise gcc * makes it inline to init() and it becomes part of init.text section * 这是个非Init函数,防止gcc让它内联到init(),并成为Init.text段的一部分 */static noinline int init_post(void){    /* need to finish all async __init code before freeing the memory      * 在释放init内存前,必须完成所有__init代码执行     */    async_synchronize_full();    free_initmem();//释放init.*段中的内存    //修改页表,保证只读数据段为只读属性read only    mark_rodata_ro();    //系统运行状态标志    system_state = SYSTEM_RUNNING;    //numa默认策略    numa_default_policy();    //当前进程不能被杀掉,只为它是init    current->signal->flags |= SIGNAL_UNKILLABLE;    //如果ramdisk_execute_command变量指定了init程序,执行它    if (ramdisk_execute_command) {        run_init_process(ramdisk_execute_command);        printk(KERN_WARNING "Failed to execute %s\n",                ramdisk_execute_command);    }    /*     * We try each of these until one succeeds.     *     * The Bourne shell can be used instead of init if we are     * trying to recover a really broken machine.     * 又一个程序,看能不能执行,如果不能,则执行下面4个之一     */    if (execute_command) {        run_init_process(execute_command);        printk(KERN_WARNING "Failed to execute %s.  Attempting "                    "defaults...\n", execute_command);    }    run_init_process("/sbin/init");    run_init_process("/etc/init");    run_init_process("/bin/init");    run_init_process("/bin/sh");    //两个变量和4个init都不能成功执行,报错    panic("No init found.  Try passing init= option to kernel. "          "See Linux Documentation/init.txt for guidance.");}static int __init kernel_init(void * unused){    /*     * Wait until kthreadd is all set-up.等待kthreadd的启动完成     */    wait_for_completion(&kthreadd_done);    /* Now the scheduler is fully set up and can do blocking allocations      *      */    gfp_allowed_mask = __GFP_BITS_MASK;    /*     * init can allocate pages on any node     */    set_mems_allowed(node_states[N_HIGH_MEMORY]);    /*     * init can run on any cpu.     */    set_cpus_allowed_ptr(current, cpu_all_mask);    //cad_pid为接收Ctrl-alt-del操作的INT信号的进程ID,设置成了init的pid    //说明init可接受这3个键    cad_pid = task_pid(current);    //smp系统准备、激活所有cpu    smp_prepare_cpus(setup_max_cpus);    do_pre_smp_initcalls();    lockup_detector_init();    smp_init();    sched_init_smp();    //初始化设备驱动、内核模块    do_basic_setup();    /* Open the /dev/console on the rootfs, this should never fail      * 打开/dev/console设备     */    if (sys_open((const char __user *) "/dev/console", O_RDWR, 0) < 0)        printk(KERN_WARNING "Warning: unable to open an initial console.\n");    /*     * 复制两次标准输入0,一个是标准输入1,一个是标准错误2     */    (void) sys_dup(0);    (void) sys_dup(0);    /*     * check if there is an early userspace init.  If yes, let it do all     * the work     * 是否有早期用户空间init进程,有的话,让其执行     */    if (!ramdisk_execute_command)        ramdisk_execute_command = "/init";    if (sys_access((const char __user *) ramdisk_execute_command, 0) != 0) {        ramdisk_execute_command = NULL;        prepare_namespace();    }    /*     * Ok, we have completed the initial bootup, and     * we"re essentially up and running. Get rid of the     * initmem segments and start the user-mode stuff..     */    //启动用户空间的init进程    init_post();    return 0;}

推荐学习:《linux视频教程》

以上就是linux内核有main函数吗的详细内容,更多请关注php中文网其它相关文章!

推荐内容