sigproc.cc
来自「cygwin, 著名的在win32下模拟unix操作系统的东东」· CC 代码 · 共 1,312 行 · 第 1/3 页
CC
1,312 行
/* Get or create a process specific semaphore used in message passing. */static HANDLE __stdcallgetsem (_pinfo *p, const char *str, int init, int max){ HANDLE h; if (p != NULL) { if (!proc_can_be_signalled (p)) { set_errno (ESRCH); return NULL; } int wait = 1000; /* Wait for new process to generate its semaphores. */ sigproc_printf ("pid %d, ppid %d, wait %d, initializing %x", p->pid, p->ppid, wait, ISSTATE (p, PID_INITIALIZING)); for (int i = 0; ISSTATE (p, PID_INITIALIZING) && i < wait; i++) low_priority_sleep (1); } SetLastError (0); if (p == NULL) { char sa_buf[1024]; DWORD winpid = GetCurrentProcessId (); h = CreateSemaphore (sec_user_nih (sa_buf), init, max, str = shared_name (str, winpid)); p = myself; if (!h) { system_printf ("can't create semaphore %s, %E", str); __seterrno (); } } else { h = OpenSemaphore (SEMAPHORE_ALL_ACCESS, FALSE, shared_name (str, p->dwProcessId)); if (!h) { if (GetLastError () == ERROR_FILE_NOT_FOUND && !proc_exists (p)) set_errno (ESRCH); /* No such process */ else set_errno (EPERM); /* Couldn't access the semaphore -- different cygwin DLL maybe? */ } } return h;}/* Remove a zombie from zombies by swapping it with the last child in the list. */static void __stdcallremove_zombie (int ci){ sigproc_printf ("removing %d, pid %d, nzombies %d", ci, zombies[ci]->pid, nzombies); if (zombies[ci]) { ForceCloseHandle1 (zombies[ci]->hProcess, childhProc); ForceCloseHandle1 (zombies[ci]->pid_handle, pid_handle); zombies[ci].release (); } if (ci < --nzombies) zombies[ci] = zombies[nzombies]; return;}/* Check status of child process vs. waitq member. * * parent_w is the pointer to the parent of the waitq member in question. * child is the subprocess being considered. * * Returns * 1 if stopped or terminated child matches parent_w->next criteria * -1 if a non-stopped/terminated child matches parent_w->next criteria * 0 if child does not match parent_w->next criteria */static int __stdcallstopped_or_terminated (waitq *parent_w, _pinfo *child){ int potential_match; waitq *w = parent_w->next; sigproc_printf ("considering pid %d", child->pid); if (w->pid == -1) potential_match = 1; else if (w->pid == 0) potential_match = child->pgid == myself->pgid; else if (w->pid < 0) potential_match = child->pgid == -w->pid; else potential_match = (w->pid == child->pid); if (!potential_match) return 0; BOOL terminated; if ((terminated = child->process_state == PID_ZOMBIE) || ((w->options & WUNTRACED) && child->stopsig)) { parent_w->next = w->next; /* successful wait. remove from wait queue */ w->pid = child->pid; if (!terminated) { sigproc_printf ("stopped child"); w->status = (child->stopsig << 8) | 0x7f; child->stopsig = 0; } else /* Should only get here when child has been moved to the zombies array */ { DWORD status; if (!GetExitCodeProcess (child->hProcess, &status)) status = 0xffff; if (status & EXIT_SIGNAL) w->status = (status >> 8) & 0xff; /* exited due to signal */ else w->status = (status & 0xff) << 8; /* exited via "exit ()" */ add_rusage (&myself->rusage_children, &child->rusage_children); add_rusage (&myself->rusage_children, &child->rusage_self); if (w->rusage) { add_rusage ((struct rusage *) w->rusage, &child->rusage_children); add_rusage ((struct rusage *) w->rusage, &child->rusage_self); } } if (!SetEvent (w->ev)) /* wake up wait4 () immediately */ system_printf ("couldn't wake up wait event %p, %E", w->ev); return 1; } return -potential_match;}static voidtalktome (){ winpids pids; for (unsigned i = 0; i < pids.npids; i++) if (pids[i]->hello_pid == myself->pid) pids[i]->commune_recv ();}/* Process signals by waiting for a semaphore to become signaled. * Then scan an in-memory array representing queued signals. * Executes in a separate thread. * * Signals sent from this process are sent a completion signal so * that returns from kill/raise do not occur until the signal has * has been handled, as per POSIX. */static DWORD WINAPIwait_sig (VOID *self){ /* Initialization */ (void) SetThreadPriority (GetCurrentThread (), WAIT_SIG_PRIORITY); /* sigcatch_nosync - semaphore incremented by sig_dispatch_pending and * by foreign processes to force an examination of * the sigtodo array. * sigcatch_main - ditto for local main thread. * sigcatch_nonmain - ditto for local non-main threads. * * sigcomplete_main - event used to signal main thread on signal * completion * sigcomplete_nonmain - semaphore signaled for non-main thread on signal * completion */ sigcatch_nosync = getsem (NULL, "sigcatch", 0, MAXLONG); sigcatch_nonmain = CreateSemaphore (&sec_none_nih, 0, MAXLONG, NULL); sigcatch_main = CreateSemaphore (&sec_none_nih, 0, MAXLONG, NULL); sigcomplete_nonmain = CreateSemaphore (&sec_none_nih, 0, MAXLONG, NULL); sigcomplete_main = CreateEvent (&sec_none_nih, FALSE, FALSE, NULL); sigproc_printf ("sigcatch_nonmain %p, sigcatch_main %p", sigcatch_nonmain, sigcatch_main); sigCONT = CreateEvent (&sec_none_nih, FALSE, FALSE, NULL); /* Setting dwProcessId flags that this process is now capable of receiving * signals. Prior to this, dwProcessId was set to the windows pid of * of the original windows process which spawned us unless this was a * "toplevel" process. */ myself->dwProcessId = GetCurrentProcessId (); myself->process_state |= PID_ACTIVE; myself->process_state &= ~PID_INITIALIZING; ProtectHandle (sigcatch_nosync); ProtectHandle (sigcatch_nonmain); ProtectHandle (sigcatch_main); ProtectHandle (sigcomplete_nonmain); ProtectHandle (sigcomplete_main); /* If we've been execed, then there is still a stub left in the previous * windows process waiting to see if it's started a cygwin process or not. * Signalling subproc_ready indicates that we are a cygwin process. */ if (child_proc_info && child_proc_info->type == PROC_EXEC) { debug_printf ("subproc_ready %p", child_proc_info->subproc_ready); if (!SetEvent (child_proc_info->subproc_ready)) system_printf ("SetEvent (subproc_ready) failed, %E"); ForceCloseHandle1 (child_proc_info->subproc_ready, subproc_ready); /* Initialize an "indirect" pid block so that if someone looks up this process via its Windows PID it will be redirected to the appropriate Cygwin PID shared memory block. */ static pinfo NO_COPY myself_identity; myself_identity.init (cygwin_pid (myself->dwProcessId), PID_EXECED); } SetEvent (wait_sig_inited); sigtid = GetCurrentThreadId (); HANDLE catchem[] = {sigcatch_main, sigcatch_nonmain, sigcatch_nosync}; sigproc_printf ("Ready. dwProcessid %d", myself->dwProcessId); for (;;) { DWORD rc = WaitForMultipleObjects (3, catchem, FALSE, sig_loop_wait); (void) SetThreadPriority (GetCurrentThread (), WAIT_SIG_PRIORITY); /* sigproc_terminate sets sig_loop_wait to zero to indicate that * this thread should terminate. */ if (rc == WAIT_TIMEOUT) { if (!sig_loop_wait) break; // Exiting else continue; } if (rc == WAIT_FAILED) { if (sig_loop_wait != 0) system_printf ("WFMO failed, %E"); break; } rc -= WAIT_OBJECT_0; sigproc_printf ("awake"); /* A sigcatch semaphore has been signaled. Scan the sigtodo * array looking for any unprocessed signals. */ pending_signals = -1; int saw_pending_signals = 0; int saw_sigchld = 0; for (int sig = -__SIGOFFSET; sig < NSIG; sig++) { while (InterlockedDecrement (myself->getsigtodo (sig)) >= 0) { if (sig == SIGCHLD) saw_sigchld = 1; if (sig > 0 && sig != SIGKILL && sig != SIGSTOP && (sigismember (&myself->getsigmask (), sig) || main_vfork->pid || (sig != SIGCONT && ISSTATE (myself, PID_STOPPED)))) { sigproc_printf ("signal %d blocked", sig); break; } /* Found a signal to process */ sigproc_printf ("processing signal %d", sig); switch (sig) { case __SIGFLUSH: /* just forcing the loop */ break; /* Internal signal to turn on stracing. */ case __SIGSTRACE: strace.hello (); break; case __SIGCOMMUNE: talktome (); break; /* A normal UNIX signal */ default: sigproc_printf ("Got signal %d", sig); sig_handle (sig, rc != 2); /* Need to decrement again to offset increment below since we really do want to decrement in this case. */ InterlockedDecrement (myself->getsigtodo (sig)); goto nextsig; /* FIXME: shouldn't this allow the loop to continue? */ } } nextsig: /* Decremented too far. */ if (InterlockedIncrement (myself->getsigtodo (sig)) > 0) saw_pending_signals = 1; } if (pending_signals < 0 && !saw_pending_signals) pending_signals = 0; if (saw_sigchld) proc_subproc (PROC_CLEARWAIT, 0); /* Signal completion of signal handling depending on which semaphore * woke up the WaitForMultipleObjects above. */ switch (rc) { case 0: SetEvent (sigcomplete_main); sigproc_printf ("set main thread completion event"); break; case 1: ReleaseSemaphore (sigcomplete_nonmain, 1, NULL); break; default: /* Signal from another process. No need to synchronize. */ break; } sigproc_printf ("looping"); } sigproc_printf ("done"); ExitThread (0);}/* Wait for subprocesses to terminate. Executes in a separate thread. */static DWORD WINAPIwait_subproc (VOID *){ sigproc_printf ("starting"); int errloop = 0; for (;;) { DWORD rc = WaitForMultipleObjects (nchildren + 1, events, FALSE, proc_loop_wait); if (rc == WAIT_TIMEOUT) if (!proc_loop_wait) break; // Exiting else continue; if (rc == WAIT_FAILED) { if (!proc_loop_wait) break; /* It's ok to get an ERROR_INVALID_HANDLE since another thread may have closed a handle in the children[] array. So, we try looping a couple of times to stabilize. FIXME - this is not foolproof. Probably, this thread should be responsible for closing the children. */ if (!errloop++) proc_subproc (PROC_NOTHING, 0); // Just synchronize and continue if (errloop < 10) continue; system_printf ("wait failed. nchildren %d, wait %d, %E", nchildren, proc_loop_wait); for (int i = 0; i <= nchildren; i++) if ((rc = WaitForSingleObject (events[i], 0)) == WAIT_OBJECT_0 || rc == WAIT_TIMEOUT) continue; else if (i == 0) system_printf ("nchildren %d, event[%d] %p, %E", nchildren, i, events[i]); else { system_printf ("nchildren %d, event[%d] %p, pchildren[%d] %p, events[0] %p, %E", nchildren, i, events[i], i - 1, (_pinfo *) pchildren[i - 1], events[0]); system_printf ("pid %d, dwProcessId %u, hProcess %p, progname '%s'", pchildren[i - 1]->pid, pchildren[i - 1]->dwProcessId, pchildren[i - 1]->hProcess, pchildren[i - 1]->progname); } break; } errloop = 0; rc -= WAIT_OBJECT_0; if (rc-- != 0) { rc = proc_subproc (PROC_CHILDTERMINATED, rc); if (!proc_loop_wait) // Don't bother if wait_subproc is break; // exiting /* Send a SIGCHLD to myself. We do this here, rather than in proc_subproc to avoid the proc_subproc lock since the signal thread will eventually be calling proc_subproc and could unnecessarily block. */ if (rc) sig_send (myself_nowait, SIGCHLD); } sigproc_printf ("looping"); } ForceCloseHandle (events[0]); events[0] = NULL; sigproc_printf ("done"); ExitThread (0);}extern "C" {/* Provide a stack frame when calling WaitFor* functions */#undef WaitForSingleObjectDWORD __stdcallWFSO (HANDLE hHandle, DWORD dwMilliseconds){ DWORD ret; sigframe thisframe (mainthread); ret = WaitForSingleObject (hHandle, dwMilliseconds); return ret;}#undef WaitForMultipleObjectsDWORD __stdcallWFMO (DWORD nCount, CONST HANDLE *lpHandles, BOOL fWaitAll, DWORD dwMilliseconds){ DWORD ret; sigframe thisframe (mainthread); ret = WaitForMultipleObjects (nCount, lpHandles, fWaitAll, dwMilliseconds); return ret;}}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?