sigproc.cc
来自「cygwin, 著名的在win32下模拟unix操作系统的东东」· CC 代码 · 共 1,312 行 · 第 1/3 页
CC
1,312 行
out1: sigproc_printf ("returning %d", rc); return rc;}/* Terminate the wait_subproc thread. * Called on process exit. * Also called by spawn_guts to disassociate any subprocesses from this * process. Subprocesses will then know to clean up after themselves and * will not become zombies. */void __stdcallproc_terminate (void){ sigproc_printf ("nchildren %d, nzombies %d", nchildren, nzombies); /* Signal processing is assumed to be blocked in this routine. */ if (hwait_subproc) { proc_loop_wait = 0; // Tell wait_subproc thread to exit sync_proc_subproc->acquire (WPSP); wake_wait_subproc (); // Wake wait_subproc loop hwait_subproc = NULL; (void) proc_subproc (PROC_CLEARWAIT, 1); /* Clean out zombie processes from the pid list. */ int i; for (i = 0; i < nzombies; i++) { if (zombies[i]->hProcess) { ForceCloseHandle1 (zombies[i]->hProcess, childhProc); ForceCloseHandle1 (zombies[i]->pid_handle, pid_handle); } zombies[i]->ppid = 1; zombies[i]->process_state = PID_EXITED; /* CGF FIXME - still needed? */ zombies[i].release (); // FIXME: this breaks older gccs for some reason } /* Disassociate my subprocesses */ for (i = 0; i < nchildren; i++) { if (!pchildren[i]->hProcess) sigproc_printf ("%d(%d) hProcess cleared already?", pchildren[i]->pid, pchildren[i]->dwProcessId); else { ForceCloseHandle1 (pchildren[i]->hProcess, childhProc); sigproc_printf ("%d(%d) closed child handle", pchildren[i]->pid, pchildren[i]->dwProcessId); pchildren[i]->ppid = 1; if (pchildren[i]->pgid == myself->pid) pchildren[i]->process_state |= PID_ORPHANED; } pchildren[i].release (); } nchildren = nzombies = 0; /* Just zero sync_proc_subproc as the delete below seems to cause problems for older gccs. */ sync_proc_subproc = NULL; } sigproc_printf ("leaving");}/* Clear pending signal from the sigtodo array */void __stdcallsig_clear (int sig){ (void) InterlockedExchange (myself->getsigtodo (sig), 0L); return;}/* Force the wait_sig thread to wake up and scan the sigtodo array. */extern "C" int __stdcallsig_dispatch_pending (int justwake){ if (!hwait_sig) return 0; DWORD tid = GetCurrentThreadId (); sigframe thisframe (mainthread); if (tid == sigtid && !justwake) justwake = 1; int was_pending = pending_signals;#ifdef DEBUGGING sigproc_printf ("pending_signals %d", was_pending);#endif if (!was_pending && !justwake)#ifdef DEBUGGING sigproc_printf ("no need to wake anything up");#else ;#endif else { assert (!wait_sig_inited); if (!justwake) (void) sig_send (myself, __SIGFLUSH); else if (ReleaseSemaphore (sigcatch_nosync, 1, NULL))#ifdef DEBUGGING sigproc_printf ("woke up wait_sig");#else ;#endif else if (no_signals_available ()) /*sigproc_printf ("I'm going away now")*/; else system_printf ("%E releasing sigcatch_nosync(%p)", sigcatch_nosync); } if (was_pending && !justwake) thisframe.call_signal_handler (); return was_pending;}/* Message initialization. Called from dll_crt0_1 * * This routine starts the signal handling thread. The wait_sig_inited * event is used to signal that the thread is ready to handle signals. * We don't wait for this during initialization but instead detect it * in sig_send to gain a little concurrency. */void __stdcallsigproc_init (){ wait_sig_inited = CreateEvent (&sec_none_nih, TRUE, FALSE, NULL); ProtectHandle (wait_sig_inited); /* sync_proc_subproc is used by proc_subproc. It serialises * access to the children and zombie arrays. */ new_muto (sync_proc_subproc); /* local event signaled when main thread has been dispatched to a signal handler function. */ signal_arrived = CreateEvent (&sec_none_nih, TRUE, FALSE, NULL); ProtectHandle (signal_arrived); hwait_sig = new cygthread (wait_sig, cygself, "sig"); hwait_sig->zap_h (); /* Initialize waitq structure for main thread. A waitq structure is * allocated for each thread that executes a wait to allow multiple threads * to perform waits. Pre-allocate a waitq structure for the main thread. */ waitq *w; if ((w = (waitq *)waitq_storage.get ()) == NULL) { w = &waitq_main; waitq_storage.set (w); } memset (w, 0, sizeof *w); // Just to be safe myself->getsig (SIGSTOP).sa_flags = SA_RESTART | SA_NODEFER; sigproc_printf ("process/signal handling enabled(%x)", myself->process_state); return;}/* Called on process termination to terminate signal and process threads. */void __stdcallsigproc_terminate (void){ hwait_sig = NULL; if (!sig_loop_wait) sigproc_printf ("sigproc_terminate: sigproc handling not active"); else { sigproc_printf ("entering"); sig_loop_wait = 0; // Tell wait_sig to exit when it is // finished with anything it is doing sig_dispatch_pending (1); } if (GetCurrentThreadId () == sigtid) { ForceCloseHandle (sigcomplete_main); for (int i = 0; i < 20; i++) (void) ReleaseSemaphore (sigcomplete_nonmain, 1, NULL); // ForceCloseHandle (sigcomplete_nonmain); // ForceCloseHandle (sigcatch_main); // ForceCloseHandle (sigcatch_nonmain); // ForceCloseHandle (sigcatch_nosync); } proc_terminate (); // Terminate process handling thread return;}/* Send a signal to another process by raising its signal semaphore. * If pinfo *p == NULL, send to the current process. * If sending to this process, wait for notification that a signal has * completed before returning. */int __stdcallsig_send (_pinfo *p, int sig, DWORD ebp, bool exception){ int rc = 1; DWORD tid = GetCurrentThreadId (); BOOL its_me; HANDLE thiscatch = NULL; HANDLE thiscomplete = NULL; BOOL wait_for_completion; sigframe thisframe; if (p == myself_nowait_nonmain) p = (tid == mainthread.id) ? (_pinfo *) myself : myself_nowait; if (!(its_me = (p == NULL || p == myself || p == myself_nowait))) wait_for_completion = FALSE; else { if (no_signals_available ()) goto out; // Either exiting or not yet initializing assert (!wait_sig_inited); wait_for_completion = p != myself_nowait; p = myself; } /* It is possible that the process is not yet ready to receive messages * or that it has exited. Detect this. */ if (!proc_can_be_signalled (p)) /* Is the process accepting messages? */ { sigproc_printf ("invalid pid %d(%x), signal %d", p->pid, p->process_state, sig); set_errno (ESRCH); goto out; } sigproc_printf ("pid %d, signal %d, its_me %d", p->pid, sig, its_me); if (its_me) { if (!wait_for_completion) thiscatch = sigcatch_nosync; else if (tid != mainthread.id) { thiscatch = sigcatch_nonmain; thiscomplete = sigcomplete_nonmain; } else { thiscatch = sigcatch_main; thiscomplete = sigcomplete_main; thisframe.set (mainthread, ebp, exception); } } else if (!(thiscatch = getsem (p, "sigcatch", 0, 0))) goto out; // Couldn't get the semaphore. getsem issued // an error, if appropriate.#if WHEN_MULTI_THREAD_SIGNALS_WORK signal_dispatch *sd; sd = signal_dispatch_storage.get (); if (sd == NULL) sd = signal_dispatch_storage.create ();#endif /* Increment the sigtodo array to signify which signal to assert. */ (void) InterlockedIncrement (p->getsigtodo (sig)); /* Notify the process that a signal has arrived. */ SetLastError (0);#if 0 int prio; prio = GetThreadPriority (GetCurrentThread ()); (void) SetThreadPriority (GetCurrentThread (), THREAD_PRIORITY_TIME_CRITICAL);#endif if (!ReleaseSemaphore (thiscatch, 1, NULL) && (int) GetLastError () > 0) { /* Couldn't signal the semaphore. This probably means that the * process is exiting. */ if (!its_me) ForceCloseHandle (thiscatch); else { if (no_signals_available ()) sigproc_printf ("I'm going away now"); else if ((int) GetLastError () == -1) rc = WaitForSingleObject (thiscomplete, 500); else system_printf ("error sending signal %d to pid %d, semaphore %p, %E", sig, p->pid, thiscatch); } goto out; } /* No need to wait for signal completion unless this was a signal to * this process. * * If it was a signal to this process, wait for a dispatched signal. * Otherwise just wait for the wait_sig to signal that it has finished * processing the signal. */ if (!wait_for_completion) { rc = WAIT_OBJECT_0; sigproc_printf ("Not waiting for sigcomplete. its_me %d signal %d", its_me, sig); if (!its_me) ForceCloseHandle (thiscatch); } else { sigproc_printf ("Waiting for thiscomplete %p", thiscomplete); SetLastError (0); rc = WaitForSingleObject (thiscomplete, WSSC); /* Check for strangeness due to this thread being redirected by the signal handler. Sometimes a WAIT_TIMEOUT will occur when the thread hasn't really timed out. So, check again. FIXME: This isn't foolproof. */ if (rc != WAIT_OBJECT_0 && WaitForSingleObject (thiscomplete, 0) == WAIT_OBJECT_0) rc = WAIT_OBJECT_0; }#if 0 SetThreadPriority (GetCurrentThread (), prio);#endif if (rc == WAIT_OBJECT_0) rc = 0; // Successful exit else { /* It's an error unless sig_loop_wait == 0 (the process is exiting). */ if (!no_signals_available ()) system_printf ("wait for sig_complete event failed, signal %d, rc %d, %E", sig, rc); set_errno (ENOSYS); rc = -1; }out: sigproc_printf ("returning %d from sending signal %d", rc, sig); return rc;}/* Set pending signal from the sigtodo array */void __stdcallsig_set_pending (int sig){ (void) InterlockedIncrement (myself->getsigtodo (sig)); return;}/* Initialize the wait_subproc thread. * Called from fork() or spawn() to initialize the handling of subprocesses. */void __stdcallsubproc_init (void){ if (hwait_subproc) return; /* A "wakeup" handle which can be toggled to make wait_subproc reexamine * the hchildren array. */ events[0] = CreateEvent (&sec_none_nih, FALSE, FALSE, NULL); hwait_subproc = new cygthread (wait_subproc, NULL, "proc"); hwait_subproc->zap_h (); ProtectHandle (events[0]); sigproc_printf ("started wait_subproc thread");}/* Initialize some of the memory block passed to child processes by fork/spawn/exec. */void __stdcallinit_child_info (DWORD chtype, child_info *ch, pid_t pid, HANDLE subproc_ready){ memset (ch, 0, sizeof *ch); ch->cb = chtype == PROC_FORK ? sizeof (child_info_fork) : sizeof (child_info); ch->intro = PROC_MAGIC_GENERIC; ch->magic = CHILD_INFO_MAGIC; ch->type = chtype; ch->cygpid = pid; ch->subproc_ready = subproc_ready; ch->pppid_handle = myself->ppid_handle; ch->fhandler_union_cb = sizeof (fhandler_union); ch->mount_h = cygwin_mount_h;}/* Check the state of all of our children to see if any are stopped or * terminated. */static int __stdcallcheckstate (waitq *parent_w){ int potential_match = 0; sigproc_printf ("nchildren %d, nzombies %d", nchildren, nzombies); /* Check already dead processes first to see if they match the criteria * given in w->next. */ for (int i = 0; i < nzombies; i++) switch (stopped_or_terminated (parent_w, zombies[i])) { case -1: potential_match = -1; break; case 1: remove_zombie (i); potential_match = 1; goto out; } sigproc_printf ("checking alive children"); /* No dead terminated children matched. Check for stopped children. */ for (int i = 0; i < nchildren; i++) switch (stopped_or_terminated (parent_w, pchildren[i])) { case -1: potential_match = -1; break; case 1: potential_match = 1; goto out; }out: sigproc_printf ("returning %d", potential_match); return potential_match;}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?