/* * Prepare new lwp to return to the address specified in params. */ int cpu_prepare_lwp(struct lwp *lp, struct lwp_params *params) { struct trapframe *regs = lp->lwp_md.md_regs; void *bad_return = NULL; int error; regs->tf_eip = (int)params->func; regs->tf_esp = (int)params->stack; /* Set up argument for function call */ regs->tf_esp -= sizeof(params->arg); error = copyout(¶ms->arg, (void *)regs->tf_esp, sizeof(params->arg)); if (error) return (error); /* * Set up fake return address. As the lwp function may never return, * we simply copy out a NULL pointer and force the lwp to receive * a SIGSEGV if it returns anyways. */ regs->tf_esp -= sizeof(void *); error = copyout(&bad_return, (void *)regs->tf_esp, sizeof(bad_return)); if (error) return (error); cpu_set_fork_handler(lp, (void (*)(void *, struct trapframe *))generic_lwp_return, lp); return (0); }
void cpu_set_upcall(struct thread *td, struct thread *td0) { struct pcb *pcb; struct trapframe *tf; ia64_highfp_save(td0); tf = td->td_frame; KASSERT(tf != NULL, ("foo")); bcopy(td0->td_frame, tf, sizeof(*tf)); tf->tf_length = sizeof(struct trapframe); tf->tf_flags = FRAME_SYSCALL; tf->tf_special.ndirty = 0; tf->tf_special.bspstore &= ~0x1ffUL; tf->tf_scratch.gr8 = 0; tf->tf_scratch.gr9 = 1; tf->tf_scratch.gr10 = 0; pcb = td->td_pcb; KASSERT(pcb != NULL, ("foo")); bcopy(td0->td_pcb, pcb, sizeof(*pcb)); pcb->pcb_special.bspstore = td->td_kstack; pcb->pcb_special.pfs = 0; pcb->pcb_current_pmap = vmspace_pmap(td->td_proc->p_vmspace); pcb->pcb_special.sp = (uintptr_t)tf - 16; pcb->pcb_special.rp = FDESC_FUNC(fork_trampoline); cpu_set_fork_handler(td, (void (*)(void*))fork_return, td); /* Setup to release the spin count in fork_exit(). */ td->td_md.md_spinlock_count = 1; td->td_md.md_saved_intr = 1; }
/* * Create a kernel process/thread/whatever. It shares it's address space * with proc0 - ie: kernel only. */ int kthread_create2(void (*func)(void *), void *arg, struct proc **newpp, int flags, const char *fmt, ...) { int error; va_list ap; struct proc *p2; if (!proc0.p_stats || proc0.p_stats->p_start.tv_sec == 0) { panic("kthread_create called too soon"); } error = fork1(&proc0, RFMEM | RFFDG | RFPROC | flags, &p2); if (error) return error; /* save a global descriptor, if desired */ if (newpp != NULL) *newpp = p2; /* this is a non-swapped system process */ p2->p_flag |= P_INMEM | P_SYSTEM; p2->p_procsig->ps_flag |= PS_NOCLDWAIT; PHOLD(p2); /* set up arg0 for 'ps', et al */ va_start(ap, fmt); vsnprintf(p2->p_comm, sizeof(p2->p_comm), fmt, ap); va_end(ap); /* call the processes' main()... */ cpu_set_fork_handler(p2, func, arg); return 0; }
/* * Create a kernel process/thread/whatever. It shares it's address space * with proc0 - ie: kernel only. * * XXX only the SMB protocol uses this, we should convert this mess to a * pure thread when possible. */ int smb_kthread_create(void (*func)(void *), void *arg, struct proc **newpp, int flags, const char *fmt, ...) { int error; __va_list ap; struct proc *p2; struct lwp *lp2; error = fork1(&lwp0, RFMEM | RFFDG | RFPROC | flags, &p2); if (error) return error; /* save a global descriptor, if desired */ if (newpp != NULL) *newpp = p2; /* this is a non-swapped system process */ p2->p_flags |= P_SYSTEM; p2->p_sigacts->ps_flag |= PS_NOCLDWAIT; lp2 = ONLY_LWP_IN_PROC(p2); /* set up arg0 for 'ps', et al */ __va_start(ap, fmt); kvsnprintf(p2->p_comm, sizeof(p2->p_comm), fmt, ap); __va_end(ap); lp2->lwp_thread->td_ucred = crhold(proc0.p_ucred); /* call the processes' main()... */ cpu_set_fork_handler(lp2, (void (*)(void *, struct trapframe *))func, arg); start_forked_proc(&lwp0, p2); return 0; }
static void linker_file_sysinit(linker_file_t lf) { struct linker_set* sysinits; struct sysinit** sipp; struct sysinit** xipp; struct sysinit* save; moduledata_t *moddata; KLD_DPF(FILE, ("linker_file_sysinit: calling SYSINITs for %s\n", lf->filename)); sysinits = (struct linker_set*) linker_file_lookup_symbol(lf, "sysinit_set", 0); KLD_DPF(FILE, ("linker_file_sysinit: SYSINITs %p\n", sysinits)); if (!sysinits) return; /* HACK ALERT! */ for (sipp = (struct sysinit **)sysinits->ls_items; *sipp; sipp++) { if ((*sipp)->func == module_register_init) { moddata = (*sipp)->udata; moddata->_file = lf; } } /* * Perform a bubble sort of the system initialization objects by * their subsystem (primary key) and order (secondary key). * * Since some things care about execution order, this is the * operation which ensures continued function. */ for (sipp = (struct sysinit **)sysinits->ls_items; *sipp; sipp++) { for (xipp = sipp + 1; *xipp; xipp++) { if ((*sipp)->subsystem <= (*xipp)->subsystem || ((*sipp)->subsystem == (*xipp)->subsystem && (*sipp)->order <= (*xipp)->order)) continue; /* skip*/ save = *sipp; *sipp = *xipp; *xipp = save; } } /* * Traverse the (now) ordered list of system initialization tasks. * Perform each task, and continue on to the next task. */ for (sipp = (struct sysinit **)sysinits->ls_items; *sipp; sipp++) { if ((*sipp)->subsystem == SI_SUB_DUMMY) continue; /* skip dummy task(s)*/ switch ((*sipp)->type) { case SI_TYPE_DEFAULT: /* no special processing*/ (*((*sipp)->func))((*sipp)->udata); break; case SI_TYPE_KTHREAD: #if !defined(SMP) /* kernel thread*/ if (fork1(&proc0, RFFDG|RFPROC|RFMEM)) panic("fork kernel thread"); cpu_set_fork_handler(pfind(proc0.p_retval[0]), (*sipp)->func, (*sipp)->udata); break; #endif case SI_TYPE_KPROCESS: /* kernel thread*/ if (fork1(&proc0, RFFDG|RFPROC)) panic("fork kernel process"); cpu_set_fork_handler(pfind(proc0.p_retval[0]), (*sipp)->func, (*sipp)->udata); break; default: panic ("linker_file_sysinit: unrecognized init type"); } } }
/* * Create a kernel process/thread/whatever. It shares its address space * with proc0 - ie: kernel only. * * func is the function to start. * arg is the parameter to pass to function on first startup. * newpp is the return value pointing to the thread's struct proc. * flags are flags to fork1 (in unistd.h) * fmt and following will be *printf'd into (*newpp)->p_comm (for ps, etc.). */ int kproc_create(void (*func)(void *), void *arg, struct proc **newpp, int flags, int pages, const char *fmt, ...) { struct fork_req fr; int error; va_list ap; struct thread *td; struct proc *p2; if (!proc0.p_stats) panic("kproc_create called too soon"); bzero(&fr, sizeof(fr)); fr.fr_flags = RFMEM | RFFDG | RFPROC | RFSTOPPED | flags; fr.fr_pages = pages; fr.fr_procp = &p2; error = fork1(&thread0, &fr); if (error) return error; /* save a global descriptor, if desired */ if (newpp != NULL) *newpp = p2; /* this is a non-swapped system process */ PROC_LOCK(p2); td = FIRST_THREAD_IN_PROC(p2); p2->p_flag |= P_SYSTEM | P_KTHREAD; td->td_pflags |= TDP_KTHREAD; mtx_lock(&p2->p_sigacts->ps_mtx); p2->p_sigacts->ps_flag |= PS_NOCLDWAIT; mtx_unlock(&p2->p_sigacts->ps_mtx); PROC_UNLOCK(p2); /* set up arg0 for 'ps', et al */ va_start(ap, fmt); vsnprintf(p2->p_comm, sizeof(p2->p_comm), fmt, ap); va_end(ap); /* set up arg0 for 'ps', et al */ va_start(ap, fmt); vsnprintf(td->td_name, sizeof(td->td_name), fmt, ap); va_end(ap); #ifdef KTR sched_clear_tdname(td); #endif /* call the processes' main()... */ cpu_set_fork_handler(td, func, arg); /* Avoid inheriting affinity from a random parent. */ cpuset_setthread(td->td_tid, cpuset_root); thread_lock(td); TD_SET_CAN_RUN(td); sched_prio(td, PVM); sched_user_prio(td, PUSER); /* Delay putting it on the run queue until now. */ if (!(flags & RFSTOPPED)) sched_add(td, SRQ_BORING); thread_unlock(td); return 0; }
/* * Create a kernel thread. It shares its address space * with proc0 - ie: kernel only. * * func is the function to start. * arg is the parameter to pass to function on first startup. * newtdp is the return value pointing to the thread's struct thread. * ** XXX fix this --> flags are flags to fork1 (in unistd.h) * fmt and following will be *printf'd into (*newtd)->td_name (for ps, etc.). */ int kthread_add(void (*func)(void *), void *arg, struct proc *p, struct thread **newtdp, int flags, int pages, const char *fmt, ...) { va_list ap; struct thread *newtd, *oldtd; if (!proc0.p_stats) panic("kthread_add called too soon"); /* If no process supplied, put it on proc0 */ if (p == NULL) p = &proc0; /* Initialize our new td */ newtd = thread_alloc(pages); if (newtd == NULL) return (ENOMEM); PROC_LOCK(p); oldtd = FIRST_THREAD_IN_PROC(p); bzero(&newtd->td_startzero, __rangeof(struct thread, td_startzero, td_endzero)); bcopy(&oldtd->td_startcopy, &newtd->td_startcopy, __rangeof(struct thread, td_startcopy, td_endcopy)); /* set up arg0 for 'ps', et al */ va_start(ap, fmt); vsnprintf(newtd->td_name, sizeof(newtd->td_name), fmt, ap); va_end(ap); newtd->td_proc = p; /* needed for cpu_set_upcall */ /* XXX optimise this probably? */ /* On x86 (and probably the others too) it is way too full of junk */ /* Needs a better name */ cpu_set_upcall(newtd, oldtd); /* put the designated function(arg) as the resume context */ cpu_set_fork_handler(newtd, func, arg); newtd->td_pflags |= TDP_KTHREAD; thread_cow_get_proc(newtd, p); /* this code almost the same as create_thread() in kern_thr.c */ p->p_flag |= P_HADTHREADS; thread_link(newtd, p); thread_lock(oldtd); /* let the scheduler know about these things. */ sched_fork_thread(oldtd, newtd); TD_SET_CAN_RUN(newtd); thread_unlock(oldtd); PROC_UNLOCK(p); tidhash_add(newtd); /* Avoid inheriting affinity from a random parent. */ cpuset_setthread(newtd->td_tid, cpuset_root); /* Delay putting it on the run queue until now. */ if (!(flags & RFSTOPPED)) { thread_lock(newtd); sched_add(newtd, SRQ_BORING); thread_unlock(newtd); } if (newtdp) *newtdp = newtd; return 0; }