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