Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files. =================================================================== RCS file: /ftp/cvs/cvsroot/src/sys/kern/init_main.c,v rcsdiff: /ftp/cvs/cvsroot/src/sys/kern/init_main.c,v: warning: Unknown phrases like `commitid ...;' are present. retrieving revision 1.157 retrieving revision 1.157.2.2 diff -u -p -r1.157 -r1.157.2.2 --- src/sys/kern/init_main.c 1999/09/28 14:47:03 1.157 +++ src/sys/kern/init_main.c 2000/11/22 16:05:17 1.157.2.2 @@ -1,4 +1,4 @@ -/* $NetBSD: init_main.c,v 1.157 1999/09/28 14:47:03 bouyer Exp $ */ +/* $NetBSD: init_main.c,v 1.157.2.2 2000/11/22 16:05:17 bouyer Exp $ */ /* * Copyright (c) 1995 Christopher G. Demetriou. All rights reserved. @@ -44,14 +44,18 @@ #include "fs_nfs.h" #include "opt_nfsserver.h" #include "opt_sysv.h" +#include "opt_maxuprc.h" +#include "opt_multiprocessor.h" +#include "opt_syscall_debug.h" #include "rnd.h" #include +#include #include #include #include -#include +#include #include #include #include @@ -70,6 +74,7 @@ #include #include #include +#include #ifdef SYSVSHM #include #endif @@ -91,18 +96,18 @@ #include -#include +#include +#include -#include -#include +#include #include #include #include -char copyright[] = "\ -Copyright (c) 1996, 1997, 1998, 1999 +const char copyright[] = "\ +Copyright (c) 1996, 1997, 1998, 1999, 2000 The NetBSD Foundation, Inc. All rights reserved. Copyright (c) 1982, 1986, 1989, 1991, 1993 The Regents of the University of California. All rights reserved. @@ -131,37 +136,14 @@ struct vnode *rootvp, *swapdev_vp; int boothowto; int cold = 1; /* still working on startup */ struct timeval boottime; -struct timeval runtime; -static void check_console __P((struct proc *p)); -static void start_init __P((void *)); -static void start_pagedaemon __P((void *)); -static void start_reaper __P((void *)); -void main __P((void)); +__volatile int start_init_exec; /* semaphore for start_init() */ -extern char sigcode[], esigcode[]; -#ifdef SYSCALL_DEBUG -extern char *syscallnames[]; -#endif +static void check_console(struct proc *p); +static void start_init(void *); +void main(void); -struct emul emul_netbsd = { - "netbsd", - NULL, - sendsig, - SYS_syscall, - SYS_MAXSYSCALL, - sysent, -#ifdef SYSCALL_DEBUG - syscallnames, -#else - NULL, -#endif - 0, - copyargs, - setregs, - sigcode, - esigcode, -}; +extern const struct emul emul_netbsd; /* defined in kern_exec.c */ /* * System startup; initialize the world, create process 0, mount root @@ -170,17 +152,20 @@ struct emul emul_netbsd = { * startup(), which does memory initialization and autoconfiguration. */ void -main() +main(void) { struct proc *p; struct pdevinit *pdev; int i, s, error; + rlim_t lim; extern struct pdevinit pdevinit[]; - extern void roundrobin __P((void *)); - extern void schedcpu __P((void *)); - extern void disk_init __P((void)); + extern void schedcpu(void *); + extern void disk_init(void); #if defined(NFSSERVER) || defined(NFS) - extern void nfs_init __P((void)); + extern void nfs_init(void); +#endif +#ifdef NVNODE_IMPLICIT + int usevnodes; #endif /* @@ -189,6 +174,7 @@ main() */ p = &proc0; curproc = p; + p->p_cpu = curcpu(); /* * Attempt to find console and initialize * in case of early panic or other messages. @@ -196,11 +182,16 @@ main() consinit(); printf("%s", copyright); + KERNEL_LOCK_INIT(); + uvm_init(); /* Do machine-dependent initialization. */ cpu_startup(); + /* Initialize callouts. */ + callout_startup(); + /* * Initialize mbuf's. Do this now because we might attempt to * allocate mbufs or mbuf clusters during autoconfiguration. @@ -219,6 +210,9 @@ main() rnd_init(); /* initialize RNG */ #endif + /* Initialize the sysctl subsystem. */ + sysctl_init(); + /* * Initialize process and pgrp structures. */ @@ -229,6 +223,7 @@ main() */ s = proclist_lock_write(); LIST_INSERT_HEAD(&allproc, p, p_list); + LIST_INSERT_HEAD(PIDHASH(p->p_pid), p, p_hash); proclist_unlock_write(s); p->p_pgrp = &pgrp0; @@ -247,11 +242,14 @@ main() * for us. */ p->p_flag = P_INMEM | P_SYSTEM | P_NOCLDWAIT; - p->p_stat = SRUN; + p->p_stat = SONPROC; p->p_nice = NZERO; p->p_emul = &emul_netbsd; strncpy(p->p_comm, "swapper", MAXCOMLEN); + callout_init(&p->p_realit_ch); + callout_init(&p->p_tsleep_ch); + /* Create credentials. */ cred0.p_refcnt = 1; p->p_cred = &cred0; @@ -282,10 +280,10 @@ main() limit0.pl_rlimit[RLIMIT_NPROC].rlim_cur = maxproc < MAXUPRC ? maxproc : MAXUPRC; - i = ptoa(uvmexp.free); - limit0.pl_rlimit[RLIMIT_RSS].rlim_max = i; - limit0.pl_rlimit[RLIMIT_MEMLOCK].rlim_max = i; - limit0.pl_rlimit[RLIMIT_MEMLOCK].rlim_cur = i / 3; + lim = ptoa(uvmexp.free); + limit0.pl_rlimit[RLIMIT_RSS].rlim_max = lim; + limit0.pl_rlimit[RLIMIT_MEMLOCK].rlim_max = lim; + limit0.pl_rlimit[RLIMIT_MEMLOCK].rlim_cur = lim / 3; limit0.pl_corename = defcorename; limit0.p_refcnt = 1; @@ -325,6 +323,9 @@ main() /* Configure the system hardware. This will enable interrupts. */ configure(); + /* Lock the kernel on behalf of proc0. */ + KERNEL_PROC_LOCK(p); + #ifdef SYSVSHM /* Initialize System V style shared memory. */ shminit(); @@ -358,11 +359,51 @@ main() kmstartup(); #endif + /* Initialize system accouting. */ + acct_init(); + + /* + * Initialize signal-related data structures, and signal state + * for proc0. + */ + signal_init(); + p->p_sigacts = &sigacts0; + siginit(p); + /* Kick off timeout driven events by calling first time. */ - roundrobin(NULL); schedcpu(NULL); - /* Determine the root and dump devices. */ + /* + * Create process 1 (init(8)). We do this now, as Unix has + * historically had init be process 1, and changing this would + * probably upset a lot of people. + * + * Note that process 1 won't immediately exec init(8), but will + * wait for us to inform it that the root file system has been + * mounted. + */ + if (fork1(p, 0, SIGCHLD, NULL, 0, start_init, NULL, NULL, &initproc)) + panic("fork init"); + + /* + * Create any kernel threads who's creation was deferred because + * initproc had not yet been created. + */ + kthread_run_deferred_queue(); + + /* + * Now that device driver threads have been created, wait for + * them to finish any deferred autoconfiguration. Note we don't + * need to lock this semaphore, since we haven't booted any + * secondary processors, yet. + */ + while (config_pending) + (void) tsleep((void *)&config_pending, PWAIT, "cfpend", 0); + + /* + * Now that autoconfiguration has completed, we can determine + * the root and dump devices. + */ cpu_rootconf(); cpu_dumpconf(); @@ -391,39 +432,67 @@ main() VREF(cwdi0.cwdi_cdir); VOP_UNLOCK(rootvnode, 0); cwdi0.cwdi_rdir = NULL; - uvm_swap_init(); + + /* + * Now that root is mounted, we can fixup initproc's CWD + * info. All other processes are kthreads, which merely + * share proc0's CWD info. + */ + initproc->p_cwdi->cwdi_cdir = rootvnode; + VREF(initproc->p_cwdi->cwdi_cdir); + initproc->p_cwdi->cwdi_rdir = NULL; /* * Now can look at time, having had a chance to verify the time * from the file system. Reset p->p_rtime as it may have been * munched in mi_switch() after the time got set. */ - p->p_stats->p_start = runtime = mono_time = boottime = time; - p->p_rtime.tv_sec = p->p_rtime.tv_usec = 0; - - /* - * Initialize signal-related data structures, and signal state - * for proc0. - */ - signal_init(); - p->p_sigacts = &sigacts0; - siginit(p); - - /* Create process 1 (init(8)). */ - if (fork1(p, 0, SIGCHLD, NULL, 0, NULL, &initproc)) - panic("fork init"); - cpu_set_kpc(initproc, start_init, initproc); + proclist_lock_read(); + s = splsched(); + for (p = LIST_FIRST(&allproc); p != NULL; + p = LIST_NEXT(p, p_list)) { + p->p_stats->p_start = mono_time = boottime = time; + if (p->p_cpu != NULL) + p->p_cpu->ci_schedstate.spc_runtime = time; + p->p_rtime.tv_sec = p->p_rtime.tv_usec = 0; + } + splx(s); + proclist_unlock_read(); - /* Create process 2, the pageout daemon kernel thread. */ - if (kthread_create1(start_pagedaemon, NULL, NULL, "pagedaemon")) + /* Create the pageout daemon kernel thread. */ + uvm_swap_init(); + if (kthread_create1(uvm_pageout, NULL, NULL, "pagedaemon")) panic("fork pagedaemon"); - /* Create process 3, the process reaper kernel thread. */ - if (kthread_create1(start_reaper, NULL, NULL, "reaper")) + /* Create the process reaper kernel thread. */ + if (kthread_create1(reaper, NULL, NULL, "reaper")) panic("fork reaper"); - /* Create any other deferred kernel threads. */ - kthread_run_deferred_queue(); + /* Create the filesystem syncer kernel thread. */ + if (kthread_create1(sched_sync, NULL, NULL, "ioflush")) + panic("fork syncer"); + +#if defined(MULTIPROCESSOR) + /* Boot the secondary processors. */ + cpu_boot_secondary_processors(); +#endif + + /* + * Okay, now we can let init(8) exec! It's off to userland! + */ + start_init_exec = 1; + wakeup((void *)&start_init_exec); + +#ifdef NVNODE_IMPLICIT + /* + * If maximum number of vnodes in namei vnode cache is not explicitly + * defined in kernel config, adjust the number such as we use roughly + * 0.5% of memory for vnode cache (but not less than NVNODE vnodes). + */ + usevnodes = (ptoa(physmem) / 200) / sizeof(struct vnode); + if (usevnodes > desiredvnodes) + desiredvnodes = usevnodes; +#endif /* The scheduler is an infinite loop. */ uvm_scheduler(); @@ -431,8 +500,7 @@ main() } static void -check_console(p) - struct proc *p; +check_console(struct proc *p) { struct nameidata nd; int error; @@ -450,7 +518,7 @@ check_console(p) /* * List of paths to try when searching for "init". */ -static char *initpaths[] = { +static const char *initpaths[] = { "/sbin/init", "/sbin/oinit", "/sbin/init.bak", @@ -462,8 +530,7 @@ static char *initpaths[] = { * The program is invoked with one argument containing the boot flags. */ static void -start_init(arg) - void *arg; +start_init(void *arg) { struct proc *p = arg; vaddr_t addr; @@ -475,7 +542,8 @@ start_init(arg) int options, i, error; register_t retval[2]; char flags[4], *flagsp; - char **pathp, *path, *slash, *ucp, **uap, *arg0, *arg1 = NULL; + const char **pathp, *path, *slash; + char *ucp, **uap, *arg0, *arg1 = NULL; /* * Now in process 1. @@ -483,6 +551,12 @@ start_init(arg) strncpy(p->p_comm, "init", MAXCOMLEN); /* + * Wait for main() to tell us that it's safe to exec. + */ + while (start_init_exec == 0) + (void) tsleep((void *)&start_init_exec, PWAIT, "initexec", 0); + + /* * This is not the right way to do this. We really should * hand-craft a descriptor onto /dev/console to hand to init, * but that's a _lot_ more work, and the benefit from this easy @@ -495,7 +569,7 @@ start_init(arg) */ addr = USRSTACK - PAGE_SIZE; if (uvm_map(&p->p_vmspace->vm_map, &addr, PAGE_SIZE, - NULL, UVM_UNKNOWN_OFFSET, + NULL, UVM_UNKNOWN_OFFSET, 0, UVM_MAPFLAG(UVM_PROT_ALL, UVM_PROT_ALL, UVM_INH_COPY, UVM_ADV_NORMAL, UVM_FLAG_FIXED|UVM_FLAG_OVERLAY|UVM_FLAG_COPYONW)) @@ -573,31 +647,13 @@ start_init(arg) * other than it doesn't exist, complain. */ error = sys_execve(p, &args, retval); - if (error == 0 || error == EJUSTRETURN) + if (error == 0 || error == EJUSTRETURN) { + KERNEL_PROC_UNLOCK(p); return; + } if (error != ENOENT) printf("exec %s: error %d\n", path, error); } printf("init: not found\n"); panic("no init"); } - -/* ARGSUSED */ -static void -start_pagedaemon(arg) - void *arg; -{ - - uvm_pageout(); - /* NOTREACHED */ -} - -/* ARGSUSED */ -static void -start_reaper(arg) - void *arg; -{ - - reaper(); - /* NOTREACHED */ -}