X-Git-Url: https://git.saurik.com/apple/xnu.git/blobdiff_plain/6d2010ae8f7a6078e10b361c6962983bab233e0f..39236c6e673c41db228275375ab7fdb0f837b292:/bsd/kern/kern_fork.c diff --git a/bsd/kern/kern_fork.c b/bsd/kern/kern_fork.c index 7746398bf..c6dd52824 100644 --- a/bsd/kern/kern_fork.c +++ b/bsd/kern/kern_fork.c @@ -109,6 +109,7 @@ extern void dtrace_lazy_dofs_duplicate(proc_t, proc_t); #include #include #include +#include #include #include @@ -129,6 +130,10 @@ extern void dtrace_lazy_dofs_duplicate(proc_t, proc_t); #include +#if CONFIG_MEMORYSTATUS +#include +#endif + /* XXX routines which should have Mach prototypes, but don't */ void thread_set_parent(thread_t parent, int pid); extern void act_thread_catt(void *ctx); @@ -136,7 +141,7 @@ void thread_set_child(thread_t child, int pid); void *act_thread_csave(void); -thread_t cloneproc(task_t, proc_t, int); +thread_t cloneproc(task_t, proc_t, int, int); proc_t forkproc(proc_t); void forkproc_free(proc_t); thread_t fork_create_child(task_t parent_task, proc_t child, int inherit_memory, int is64bit); @@ -158,8 +163,8 @@ void proc_vfork_end(proc_t parent_proc); * Notes: Although this function increments a count, a count in * excess of 1 is not currently supported. According to the * POSIX standard, calling anything other than execve() or - * _exit() fillowing a vfork(), including calling vfork() - * itself again, will result in undefned behaviour + * _exit() following a vfork(), including calling vfork() + * itself again, will result in undefined behaviour */ void proc_vfork_begin(proc_t parent_proc) @@ -179,7 +184,7 @@ proc_vfork_begin(proc_t parent_proc) * * Returns: (void) * - * Notes: Decerements the count; currently, reentrancy of vfork() + * Notes: Decrements the count; currently, reentrancy of vfork() * is unsupported on the current process */ void @@ -189,7 +194,6 @@ proc_vfork_end(proc_t parent_proc) parent_proc->p_vforkcnt--; if (parent_proc->p_vforkcnt < 0) panic("vfork cnt is -ve"); - /* resude the vfork count; clear the flag when it goes to 0 */ if (parent_proc->p_vforkcnt == 0) parent_proc->p_lflag &= ~P_LVFORK; proc_unlock(parent_proc); @@ -277,12 +281,8 @@ vfork(proc_t parent_proc, __unused struct vfork_args *uap, int32_t *retval) if ((err = fork1(parent_proc, &child_thread, PROC_CREATE_VFORK)) != 0) { retval[1] = 0; } else { - /* - * kludge: rely on uu_proc being set in the vfork case, - * rather than returning the actual thread. We can remove - * this when we remove the uu_proc/current_proc() kludge. - */ - proc_t child_proc = current_proc(); + uthread_t ut = get_bsdthread_info(current_thread()); + proc_t child_proc = ut->uu_proc; retval[0] = child_proc->p_pid; retval[1] = 1; /* flag child return for user space */ @@ -295,12 +295,12 @@ vfork(proc_t parent_proc, __unused struct vfork_args *uap, int32_t *retval) proc_signalend(child_proc, 0); proc_transend(child_proc, 0); - /* flag the fork has occurred */ proc_knote(parent_proc, NOTE_FORK | child_proc->p_pid); DTRACE_PROC1(create, proc_t, child_proc); + ut->uu_flag &= ~UT_VFORKING; } - return(err); + return (err); } @@ -480,7 +480,20 @@ fork1(proc_t parent_proc, thread_t *child_threadp, int kind) child_proc->p_vforkact = parent_thread; child_proc->p_stat = SRUN; - parent_uthread->uu_flag |= UT_VFORK; + /* + * Until UT_VFORKING is cleared at the end of the vfork + * syscall, the process identity of this thread is slightly + * murky. + * + * As long as UT_VFORK and it's associated field (uu_proc) + * is set, current_proc() will always return the child process. + * + * However dtrace_proc_selfpid() returns the parent pid to + * ensure that e.g. the proc:::create probe actions accrue + * to the parent. (Otherwise the child magically seems to + * have created itself!) + */ + parent_uthread->uu_flag |= UT_VFORK | UT_VFORKING; parent_uthread->uu_proc = child_proc; parent_uthread->uu_userstate = (void *)act_thread_csave(); parent_uthread->uu_vforkmask = parent_uthread->uu_sigmask; @@ -525,7 +538,7 @@ fork1(proc_t parent_proc, thread_t *child_threadp, int kind) * will, in effect, create a duplicate of it, with only minor * differences. Contrarily, spawned processes do not inherit. */ - if ((child_thread = cloneproc(parent_proc->task, parent_proc, spawn ? FALSE : TRUE)) == NULL) { + if ((child_thread = cloneproc(parent_proc->task, parent_proc, spawn ? FALSE : TRUE, FALSE)) == NULL) { /* Failed to create thread */ err = EAGAIN; goto bad; @@ -671,48 +684,53 @@ bad: * this is done by reassociating the parent process structure * with the task, thread, and uthread. * + * Refer to the ASCII art above vfork() to figure out the + * state we're undoing. + * * Parameters: child_proc Child process * retval System call return value array * rval Return value to present to parent * * Returns: void * - * Note: The caller resumes or exits the parent, as appropriate, after - * callling this function. + * Notes: The caller resumes or exits the parent, as appropriate, after + * calling this function. */ void vfork_return(proc_t child_proc, int32_t *retval, int rval) { - proc_t parent_proc = child_proc->p_pptr; - thread_t parent_thread = (thread_t)current_thread(); - uthread_t parent_uthread = (uthread_t)get_bsdthread_info(parent_thread); + task_t parent_task = get_threadtask(child_proc->p_vforkact); + proc_t parent_proc = get_bsdtask_info(parent_task); + thread_t th = current_thread(); + uthread_t uth = get_bsdthread_info(th); - act_thread_catt(parent_uthread->uu_userstate); + act_thread_catt(uth->uu_userstate); - /* end vfork in parent */ + /* clear vfork state in parent proc structure */ proc_vfork_end(parent_proc); /* REPATRIATE PARENT TASK, THREAD, UTHREAD */ - parent_uthread->uu_userstate = 0; - parent_uthread->uu_flag &= ~UT_VFORK; + uth->uu_userstate = 0; + uth->uu_flag &= ~UT_VFORK; /* restore thread-set-id state */ - if (parent_uthread->uu_flag & UT_WASSETUID) { - parent_uthread->uu_flag |= UT_SETUID; - parent_uthread->uu_flag &= UT_WASSETUID; + if (uth->uu_flag & UT_WASSETUID) { + uth->uu_flag |= UT_SETUID; + uth->uu_flag &= UT_WASSETUID; } - parent_uthread->uu_proc = 0; - parent_uthread->uu_sigmask = parent_uthread->uu_vforkmask; - child_proc->p_lflag &= ~P_LINVFORK; - child_proc->p_vforkact = (void *)0; + uth->uu_proc = 0; + uth->uu_sigmask = uth->uu_vforkmask; + + proc_lock(child_proc); + child_proc->p_lflag &= ~P_LINVFORK; + child_proc->p_vforkact = 0; + proc_unlock(child_proc); - thread_set_parent(parent_thread, rval); + thread_set_parent(th, rval); if (retval) { retval[0] = rval; retval[1] = 0; /* mark parent */ } - - return; } @@ -758,7 +776,8 @@ fork_create_child(task_t parent_task, proc_t child_proc, int inherit_memory, int is64bit, &child_task); if (result != KERN_SUCCESS) { - printf("execve: task_create_internal failed. Code: %d\n", result); + printf("%s: task_create_internal failed. Code: %d\n", + __func__, result); goto bad; } @@ -794,10 +813,17 @@ fork_create_child(task_t parent_task, proc_t child_proc, int inherit_memory, int /* Create a new thread for the child process */ result = thread_create(child_task, &child_thread); if (result != KERN_SUCCESS) { - printf("execve: thread_create failed. Code: %d\n", result); + printf("%s: thread_create failed. Code: %d\n", + __func__, result); task_deallocate(child_task); child_task = NULL; } + + /* + * Tag thread as being the first thread in its task. + */ + thread_set_tag(child_thread, THREAD_TAG_MAINTHREAD); + bad: thread_yield_internal(1); @@ -897,6 +923,8 @@ fork(proc_t parent_proc, __unused struct fork_args *uap, int32_t *retval) * memory from the parent; if this is * non-NULL, then the parent_task must * also be non-NULL + * memstat_internal Whether to track the process in the + * jetsam priority list (if configured) * * Returns: !NULL pointer to new child thread * NULL Failure (unspecified) @@ -918,8 +946,11 @@ fork(proc_t parent_proc, __unused struct fork_args *uap, int32_t *retval) * live with this being somewhat awkward. */ thread_t -cloneproc(task_t parent_task, proc_t parent_proc, int inherit_memory) +cloneproc(task_t parent_task, proc_t parent_proc, int inherit_memory, int memstat_internal) { +#if !CONFIG_MEMORYSTATUS +#pragma unused(memstat_internal) +#endif task_t child_task; proc_t child_proc; thread_t child_thread = NULL; @@ -949,6 +980,14 @@ cloneproc(task_t parent_task, proc_t parent_proc, int inherit_memory) OSBitAndAtomic(~((uint32_t)P_LP64), (UInt32 *)&child_proc->p_flag); } +#if CONFIG_MEMORYSTATUS + if (memstat_internal) { + proc_list_lock(); + child_proc->p_memstat_state |= P_MEMSTAT_INTERNAL; + proc_list_unlock(); + } +#endif + /* make child visible */ pinsertchild(parent_proc, child_proc); @@ -1174,9 +1213,12 @@ retry: * Increase reference counts on shared objects. * The p_stats and p_sigacts substructs are set in vm_fork. */ - child_proc->p_flag = (parent_proc->p_flag & (P_LP64 | P_TRANSLATED | P_AFFINITY | P_DISABLE_ASLR)); + child_proc->p_flag = (parent_proc->p_flag & (P_LP64 | P_TRANSLATED | P_AFFINITY | P_DISABLE_ASLR | P_DELAYIDLESLEEP)); if (parent_proc->p_flag & P_PROFIL) startprofclock(child_proc); + + child_proc->p_vfs_iopolicy = (parent_proc->p_vfs_iopolicy & (P_VFS_IOPOLICY_FORCE_HFS_CASE_SENSITIVITY)); + /* * Note that if the current thread has an assumed identity, this * credential will be granted to the new process. @@ -1243,12 +1285,8 @@ retry: /* Intialize new process stats, including start time */ /* non-zeroed portion contains garbage AFAICT */ - bzero(&child_proc->p_stats->pstat_startzero, - (unsigned) ((caddr_t)&child_proc->p_stats->pstat_endzero - - (caddr_t)&child_proc->p_stats->pstat_startzero)); - bzero(&child_proc->p_stats->user_p_prof, sizeof(struct user_uprof)); - microtime(&child_proc->p_start); - child_proc->p_stats->p_start = child_proc->p_start; /* for compat */ + bzero(child_proc->p_stats, sizeof(*child_proc->p_stats)); + microtime_with_abstime(&child_proc->p_start, &child_proc->p_stats->ps_start); if (parent_proc->p_sigacts != NULL) (void)memcpy(child_proc->p_sigacts, @@ -1302,6 +1340,7 @@ retry: child_proc->p_lflag |= P_LREGISTER; } child_proc->p_dispatchqueue_offset = parent_proc->p_dispatchqueue_offset; + child_proc->p_dispatchqueue_serialno_offset = parent_proc->p_dispatchqueue_serialno_offset; #if PSYNCH pth_proc_hashinit(child_proc); #endif /* PSYNCH */ @@ -1319,6 +1358,19 @@ retry: } #endif +#if CONFIG_MEMORYSTATUS + /* Memorystatus + jetsam init */ + child_proc->p_memstat_state = 0; + child_proc->p_memstat_effectivepriority = JETSAM_PRIORITY_DEFAULT; + child_proc->p_memstat_requestedpriority = JETSAM_PRIORITY_DEFAULT; + child_proc->p_memstat_userdata = 0; +#if CONFIG_FREEZE + child_proc->p_memstat_suspendedfootprint = 0; +#endif + child_proc->p_memstat_dirty = 0; + child_proc->p_memstat_idledeadline = 0; +#endif /* CONFIG_MEMORYSTATUS */ + bad: return(child_proc); } @@ -1373,8 +1425,6 @@ uthread_zone_init(void) THREAD_CHUNK * sizeof(struct uthread), "uthreads"); uthread_zone_inited = 1; - - zone_change(uthread_zone, Z_NOENCRYPT, TRUE); } } @@ -1394,7 +1444,7 @@ uthread_alloc(task_t task, thread_t thread, int noinherit) p = (proc_t) get_bsdtask_info(task); uth = (uthread_t)ut; - uth->uu_kwe.kwe_uth = uth; + uth->uu_thread = thread; /* * Thread inherits credential from the creating thread, if both @@ -1447,6 +1497,9 @@ uthread_alloc(task_t task, thread_t thread, int noinherit) if (p->p_dtrace_ptss_pages != NULL) { uth->t_dtrace_scratch = dtrace_ptss_claim_entry(p); } +#endif +#if CONFIG_MACF + mac_thread_label_init(uth); #endif } @@ -1477,7 +1530,7 @@ uthread_cleanup(task_t task, void *uthread, void * bsd_info) * Calling this routine will clean up any throttle info reference * still inuse by the thread. */ - throttle_lowpri_io(FALSE); + throttle_lowpri_io(0); } /* * Per-thread audit state should never last beyond system @@ -1502,10 +1555,8 @@ uthread_cleanup(task_t task, void *uthread, void * bsd_info) if (uth->uu_allocsize && uth->uu_wqset){ kfree(uth->uu_wqset, uth->uu_allocsize); - sel->count = 0; uth->uu_allocsize = 0; uth->uu_wqset = 0; - sel->wql = 0; } if(uth->pth_name != NULL) @@ -1534,6 +1585,9 @@ uthread_cleanup(task_t task, void *uthread, void * bsd_info) if (tmpptr != NULL) { dtrace_ptss_release_entry(p, tmpptr); } +#endif +#if CONFIG_MACF + mac_thread_label_destroy(uth); #endif } }