/* * Implement fork's actions on an address space. * Here we arrange for the address space to be copied or referenced, * allocate a user struct (pcb and kernel stack), then call the * machine-dependent layer to fill those in and make the new process * ready to run. The new process is set up so that it returns directly * to user mode to avoid stack copying and relocation problems. * * No requirements. */ void vm_fork(struct proc *p1, struct proc *p2, int flags) { if ((flags & RFPROC) == 0) { /* * Divorce the memory, if it is shared, essentially * this changes shared memory amongst threads, into * COW locally. */ if ((flags & RFMEM) == 0) { if (p1->p_vmspace->vm_sysref.refcnt > 1) { vmspace_unshare(p1); } } cpu_fork(ONLY_LWP_IN_PROC(p1), NULL, flags); return; } if (flags & RFMEM) { vmspace_ref(p1->p_vmspace); p2->p_vmspace = p1->p_vmspace; } while (vm_page_count_severe()) { vm_wait(0); } if ((flags & RFMEM) == 0) { p2->p_vmspace = vmspace_fork(p1->p_vmspace); pmap_pinit2(vmspace_pmap(p2->p_vmspace)); if (p1->p_vmspace->vm_shm) shmfork(p1, p2); } pmap_init_proc(p2); }
/* * 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; }