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 + -
显示快捷键?