📄 fork.cc
字号:
CloseHandle (console_handle); else c_flags |= DETACHED_PROCESS; /* Some file types (currently only sockets) need extra effort in the parent after CreateProcess and before copying the datastructures to the child. So we have to start the child in suspend state, unfortunately, to avoid a race condition. */ if (cygheap->fdtab.need_fixup_before ()) c_flags |= CREATE_SUSPENDED; /* Create an inheritable handle to pass to the child process. This will allow the child to duplicate handles from the parent to itself. */ hParent = NULL; if (!DuplicateHandle (hMainProc, hMainProc, hMainProc, &hParent, 0, 1, DUPLICATE_SAME_ACCESS)) { system_printf ("couldn't create handle to myself for child, %E"); return -1; } /* Remember the address of the first loaded dll and decide if we need to load dlls. We do this here so that this information will be available in the parent and, when the stack is copied, in the child. */ first_dll = dlls.start.next; load_dlls = dlls.reload_on_fork && dlls.loaded_dlls; /* This will help some of the confusion. */ fflush (stdout); subproc_ready = CreateEvent (&sec_all, FALSE, FALSE, NULL); if (subproc_ready == NULL) { CloseHandle (hParent); system_printf ("unable to allocate subproc_ready event, %E"); return -1; } forker_finished = CreateEvent (&sec_all, FALSE, FALSE, NULL); if (forker_finished == NULL) { CloseHandle (hParent); CloseHandle (subproc_ready); system_printf ("unable to allocate forker_finished event, %E"); return -1; } ProtectHandleINH (subproc_ready); ProtectHandleINH (forker_finished); init_child_info (PROC_FORK, &ch, 1, subproc_ready); ch.forker_finished = forker_finished; stack_base (ch); si.cb = sizeof (STARTUPINFO); si.lpReserved2 = (LPBYTE)&ch; si.cbReserved2 = sizeof (ch); /* Remove impersonation */ if (cygheap->user.issetuid ()) RevertToSelf (); ch.parent = hParent;#ifdef DEBUGGING if (npid_max) { for (int pass = 0; pass < 2; pass++) { pid_t pid; while ((pid = fork_pids[npid++])) if (!pinfo (pid)) { ch.cygpid = pid; goto out; } npid = 0; } } out:#endif char sa_buf[1024]; PSECURITY_ATTRIBUTES sec_attribs = sec_user_nih (sa_buf); syscall_printf ("CreateProcess (%s, %s, 0, 0, 1, %x, 0, 0, %p, %p)", myself->progname, myself->progname, c_flags, &si, &pi); __malloc_lock (); void *newheap; newheap = cygheap_setup_for_child (&ch, cygheap->fdtab.need_fixup_before ()); rc = CreateProcess (myself->progname, /* image to run */ myself->progname, /* what we send in arg0 */ sec_attribs, sec_attribs, TRUE, /* inherit handles from parent */ c_flags, NULL, /* environment filled in later */ 0, /* use current drive/directory */ &si, &pi); CloseHandle (hParent); if (!rc) { __seterrno (); syscall_printf ("CreateProcessA failed, %E"); ForceCloseHandle (subproc_ready); ForceCloseHandle (forker_finished); /* Restore impersonation */ if (cygheap->user.issetuid ()) ImpersonateLoggedOnUser (cygheap->user.token); cygheap_setup_for_child_cleanup (newheap, &ch, 0); return -1; } /* Fixup the parent datastructure if needed and resume the child's main thread. */ if (!cygheap->fdtab.need_fixup_before ()) cygheap_setup_for_child_cleanup (newheap, &ch, 0); else { cygheap->fdtab.fixup_before_fork (pi.dwProcessId); cygheap_setup_for_child_cleanup (newheap, &ch, 1); ResumeThread (pi.hThread); }#ifdef DEBUGGING pinfo forked ((ch.cygpid != 1 ? ch.cygpid : cygwin_pid (pi.dwProcessId)), 1);#else pinfo forked (cygwin_pid (pi.dwProcessId), 1);#endif /* Initialize things that are done later in dll_crt0_1 that aren't done for the forkee. */ strcpy (forked->progname, myself->progname); /* Restore impersonation */ if (cygheap->user.issetuid ()) ImpersonateLoggedOnUser (cygheap->user.token); ProtectHandle (pi.hThread); /* Protect the handle but name it similarly to the way it will be called in subproc handling. */ ProtectHandle1 (pi.hProcess, childhProc); /* Fill in fields in the child's process table entry. */ forked->hProcess = pi.hProcess; forked->dwProcessId = pi.dwProcessId; forked->copysigs (myself); /* Hopefully, this will succeed. The alternative to doing things this way is to reserve space prior to calling CreateProcess and then fill it in afterwards. This requires more bookkeeping than I like, though, so we'll just do it the easy way. So, terminate any child process if we can't actually record the pid in the internal table. */ if (!forked.remember ()) { TerminateProcess (pi.hProcess, 1); set_errno (EAGAIN); goto cleanup; } slow_pid_reuse (pi.hProcess); /* Wait for subproc to initialize itself. */ if (!sync_with_child (pi, subproc_ready, TRUE, "waiting for longjmp")) goto cleanup; /* CHILD IS STOPPED */ debug_printf ("child is alive (but stopped)"); /* Initialize, in order: data, bss, heap, stack, dll data, dll bss Note: variables marked as NO_COPY will not be copied since they are placed in a protected segment. */ MALLOC_CHECK; rc = fork_copy (pi, "user/cygwin data", user_data->data_start, user_data->data_end, user_data->bss_start, user_data->bss_end, cygheap->user_heap.base, cygheap->user_heap.ptr, stack_here, ch.stackbottom, dll_data_start, dll_data_end, dll_bss_start, dll_bss_end, NULL); __malloc_unlock (); MALLOC_CHECK; if (!rc) goto cleanup; /* Now fill data/bss of any DLLs that were linked into the program. */ for (dll *d = dlls.istart (DLL_LINK); d; d = dlls.inext ()) { debug_printf ("copying data/bss of a linked dll"); if (!fork_copy (pi, "linked dll data/bss", d->p.data_start, d->p.data_end, d->p.bss_start, d->p.bss_end, NULL)) goto cleanup; } /* Start thread, and wait for it to reload dlls. */ if (!resume_child (pi, forker_finished) || !sync_with_child (pi, subproc_ready, load_dlls, "child loading dlls")) goto cleanup; /* If DLLs were loaded in the parent, then the child has reloaded all of them and is now waiting to have all of the individual data and bss sections filled in. */ if (load_dlls) { /* CHILD IS STOPPED */ /* write memory of reloaded dlls */ for (dll *d = dlls.istart (DLL_LOAD); d; d = dlls.inext ()) { debug_printf ("copying data/bss for a loaded dll"); if (!fork_copy (pi, "loaded dll data/bss", d->p.data_start, d->p.data_end, d->p.bss_start, d->p.bss_end, NULL)) goto cleanup; } /* Start the child up again. */ (void) resume_child (pi, forker_finished); } ForceCloseHandle (subproc_ready); ForceCloseHandle (pi.hThread); ForceCloseHandle (forker_finished); forker_finished = NULL; pi.hThread = NULL; pthread::atforkparent (); return forked->pid;/* Common cleanup code for failure cases */ cleanup: /* Remember to de-allocate the fd table. */ if (pi.hProcess) ForceCloseHandle1 (pi.hProcess, childhProc); if (pi.hThread) ForceCloseHandle (pi.hThread); if (subproc_ready) ForceCloseHandle (subproc_ready); if (forker_finished) ForceCloseHandle (forker_finished); return -1;}extern "C" intfork (){ struct { HANDLE hParent; dll *first_dll; bool load_dlls; } grouped; MALLOC_CHECK; sigframe thisframe (mainthread); debug_printf ("entering"); grouped.hParent = grouped.first_dll = NULL; grouped.load_dlls = 0; if (ISSTATE(myself, PID_SPLIT_HEAP)) { system_printf ("The heap has been split, CYGWIN can't fork this process."); system_printf ("Increase the heap_chunk_size in the registry and try again."); set_errno (ENOMEM); syscall_printf ("-1 = fork (), split heap"); return -1; } void *esp; __asm__ volatile ("movl %%esp,%0": "=r" (esp)); myself->set_has_pgid_children (); child_info_fork ch; int res = setjmp (ch.jmp); if (res) res = fork_child (grouped.hParent, grouped.first_dll, grouped.load_dlls); else res = fork_parent (grouped.hParent, grouped.first_dll, grouped.load_dlls, esp, ch); MALLOC_CHECK; syscall_printf ("%d = fork()", res); return res;}#ifdef DEBUGGINGvoidfork_init (){ char buf[1024]; if (!GetEnvironmentVariable ("CYGWIN_FORK_PIDS", buf, 1024)) return; pid_t pid; char *p, *pe; for (p = buf; (pid = strtol (p, &pe, 10)); p = pe) fork_pids[npid_max++] = pid;}#endif /*DEBUGGING*/#ifdef NEWVFORK/* Dummy function to force second assignment below to actually be carried out */static vfork_save *get_vfork_val (){ return vfork_storage.val ();}#endifextern "C" intvfork (){#ifndef NEWVFORK return fork ();#else sigframe thisframe; vfork_save *vf = get_vfork_val (); char **esp, **pp; if (vf == NULL) vf = vfork_storage.create (); else if (vf->pid) return fork (); if (!setjmp (vf->j)) { vf->pid = -1; __asm__ volatile ("movl %%esp,%0": "=r" (vf->vfork_esp):); __asm__ volatile ("movl %%ebp,%0": "=r" (vf->vfork_ebp):); for (pp = (char **)vf->frame, esp = vf->vfork_esp; esp <= vf->vfork_ebp + 2; pp++, esp++) *pp = *esp; vf->ctty = myself->ctty; vf->sid = myself->sid; vf->pgid = myself->pgid; int res = cygheap->fdtab.vfork_child_dup () ? 0 : -1; debug_printf ("%d = vfork()", res); return res; } vf = get_vfork_val (); for (pp = (char **)vf->frame, esp = vf->vfork_esp; esp <= vf->vfork_ebp + 2; pp++, esp++) *esp = *pp; thisframe.init (mainthread); cygheap->fdtab.vfork_parent_restore (); myself->ctty = vf->ctty; myself->sid = vf->sid; myself->pgid = vf->pgid; if (vf->pid < 0) { int exitval = vf->exitval; vf->pid = 0; if ((vf->pid = fork ()) == 0) exit (exitval); } int pid = vf->pid; vf->pid = 0; debug_printf ("exiting vfork, pid %d", pid); sig_dispatch_pending (); return pid;#endif}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -