* 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. */
| 536 | * to user mode to avoid stack copying and relocation problems. |
| 537 | */ |
| 538 | int |
| 539 | vm_forkproc(struct thread *td, struct proc *p2, struct thread *td2, |
| 540 | struct vmspace *vm2, int flags) |
| 541 | { |
| 542 | struct proc *p1 = td->td_proc; |
| 543 | struct domainset *dset; |
| 544 | int error; |
| 545 | |
| 546 | if ((flags & RFPROC) == 0) { |
| 547 | /* |
| 548 | * Divorce the memory, if it is shared, essentially |
| 549 | * this changes shared memory amongst threads, into |
| 550 | * COW locally. |
| 551 | */ |
| 552 | if ((flags & RFMEM) == 0) { |
| 553 | if (refcount_load(&p1->p_vmspace->vm_refcnt) > 1) { |
| 554 | error = vmspace_unshare(p1); |
| 555 | if (error) |
| 556 | return (error); |
| 557 | } |
| 558 | } |
| 559 | cpu_fork(td, p2, td2, flags); |
| 560 | return (0); |
| 561 | } |
| 562 | |
| 563 | if (flags & RFMEM) { |
| 564 | p2->p_vmspace = p1->p_vmspace; |
| 565 | refcount_acquire(&p1->p_vmspace->vm_refcnt); |
| 566 | } |
| 567 | dset = td2->td_domain.dr_policy; |
| 568 | while (vm_page_count_severe_set(&dset->ds_mask)) { |
| 569 | vm_wait_doms(&dset->ds_mask, 0); |
| 570 | } |
| 571 | |
| 572 | if ((flags & RFMEM) == 0) { |
| 573 | p2->p_vmspace = vm2; |
| 574 | if (p1->p_vmspace->vm_shm) |
| 575 | shmfork(p1, p2); |
| 576 | } |
| 577 | |
| 578 | /* |
| 579 | * cpu_fork will copy and update the pcb, set up the kernel stack, |
| 580 | * and make the child ready to run. |
| 581 | */ |
| 582 | cpu_fork(td, p2, td2, flags); |
| 583 | return (0); |
| 584 | } |
| 585 | |
| 586 | /* |
| 587 | * Called after process has been wait(2)'ed upon and is being reaped. |
no test coverage detected