Пример #1
0
/*
 * 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(&params->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);
}
Пример #2
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;
}
Пример #3
0
/*
 * 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;
}
Пример #4
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;
}
Пример #5
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");
	}
    }
}
Пример #6
0
/*
 * 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;
}
Пример #7
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;
}