117 lines
		
	
	
		
			3.2 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			117 lines
		
	
	
		
			3.2 KiB
		
	
	
	
		
			C++
		
	
	
	
/* cygwait.h
 | 
						|
 | 
						|
   This file is part of Cygwin.
 | 
						|
 | 
						|
   This software is a copyrighted work licensed under the terms of the
 | 
						|
   Cygwin license.  Please consult the file "CYGWIN_LICENSE" for
 | 
						|
   details.  */
 | 
						|
 | 
						|
#include "winsup.h"
 | 
						|
#include "sigproc.h"
 | 
						|
#include "cygwait.h"
 | 
						|
#include "ntdll.h"
 | 
						|
 | 
						|
#define is_cw_cancel		(mask & cw_cancel)
 | 
						|
#define is_cw_cancel_self	(mask & cw_cancel_self)
 | 
						|
#define is_cw_sig		(mask & cw_sig)
 | 
						|
#define is_cw_sig_eintr		(mask & cw_sig_eintr)
 | 
						|
#define is_cw_sig_cont		(mask & cw_sig_cont)
 | 
						|
#define is_cw_sig_restart	(mask & cw_sig_restart)
 | 
						|
 | 
						|
#define is_cw_sig_handle	(mask & (cw_sig | cw_sig_eintr \
 | 
						|
					 | cw_sig_cont | cw_sig_restart))
 | 
						|
 | 
						|
LARGE_INTEGER cw_nowait_storage;
 | 
						|
 | 
						|
DWORD
 | 
						|
cygwait (HANDLE object, PLARGE_INTEGER timeout, unsigned mask)
 | 
						|
{
 | 
						|
  DWORD res;
 | 
						|
  DWORD num = 0;
 | 
						|
  HANDLE wait_objects[4];
 | 
						|
  pthread_t thread = pthread::self ();
 | 
						|
 | 
						|
  /* Do not change the wait order.
 | 
						|
     The object must have higher priority than the cancel event,
 | 
						|
     because WaitForMultipleObjects will return the smallest index
 | 
						|
     if both objects are signaled. */
 | 
						|
  if (object)
 | 
						|
    wait_objects[num++] = object;
 | 
						|
 | 
						|
  wait_signal_arrived thread_waiting (is_cw_sig_handle, wait_objects[num]);
 | 
						|
  debug_only_printf ("object %p, thread waiting %d, signal_arrived %p",
 | 
						|
		     object, (int) thread_waiting, _my_tls.signal_arrived);
 | 
						|
  DWORD sig_n;
 | 
						|
  if (!thread_waiting)
 | 
						|
    sig_n = WAIT_TIMEOUT + 1;
 | 
						|
  else
 | 
						|
    sig_n = WAIT_OBJECT_0 + num++;
 | 
						|
 | 
						|
  DWORD cancel_n;
 | 
						|
  if (!is_cw_cancel || !pthread::is_good_object (&thread) ||
 | 
						|
      thread->cancelstate == PTHREAD_CANCEL_DISABLE)
 | 
						|
    cancel_n = WAIT_TIMEOUT + 1;
 | 
						|
  else
 | 
						|
    {
 | 
						|
      cancel_n = WAIT_OBJECT_0 + num++;
 | 
						|
      wait_objects[cancel_n] = thread->cancel_event;
 | 
						|
    }
 | 
						|
 | 
						|
  DWORD timeout_n;
 | 
						|
  if (!timeout)
 | 
						|
    timeout_n = WAIT_TIMEOUT + 1;
 | 
						|
  else
 | 
						|
    {
 | 
						|
      timeout_n = WAIT_OBJECT_0 + num++;
 | 
						|
      if (!_my_tls.locals.cw_timer)
 | 
						|
	NtCreateTimer (&_my_tls.locals.cw_timer, TIMER_ALL_ACCESS, NULL,
 | 
						|
		       NotificationTimer);
 | 
						|
      NtSetTimer (_my_tls.locals.cw_timer, timeout, NULL, NULL, FALSE, 0, NULL);
 | 
						|
      wait_objects[timeout_n] = _my_tls.locals.cw_timer;
 | 
						|
    }
 | 
						|
 | 
						|
  while (1)
 | 
						|
    {
 | 
						|
      res = WaitForMultipleObjects (num, wait_objects, FALSE, INFINITE);
 | 
						|
      debug_only_printf ("res %d", res);
 | 
						|
      if (res == cancel_n)
 | 
						|
	res = WAIT_CANCELED;
 | 
						|
      else if (res == timeout_n)
 | 
						|
	res = WAIT_TIMEOUT;
 | 
						|
      else if (res != sig_n)
 | 
						|
	/* all set */;
 | 
						|
      else
 | 
						|
	{
 | 
						|
	  int sig = _my_tls.sig;
 | 
						|
	  if (is_cw_sig_cont && sig == SIGCONT)
 | 
						|
	    _my_tls.sig = 0;
 | 
						|
	  if (!sig)
 | 
						|
	    continue;
 | 
						|
	  if (is_cw_sig_eintr || (is_cw_sig_cont && sig == SIGCONT))
 | 
						|
	    ;
 | 
						|
	  else if (_my_tls.call_signal_handler () || is_cw_sig_restart)
 | 
						|
	    continue;
 | 
						|
	  res = WAIT_SIGNALED;	/* caller will deal with signals */
 | 
						|
	}
 | 
						|
      break;
 | 
						|
    }
 | 
						|
 | 
						|
  if (timeout)
 | 
						|
    {
 | 
						|
      TIMER_BASIC_INFORMATION tbi;
 | 
						|
 | 
						|
      NtQueryTimer (_my_tls.locals.cw_timer, TimerBasicInformation, &tbi,
 | 
						|
		    sizeof tbi, NULL);
 | 
						|
      /* if timer expired, TimeRemaining is negative and represents the
 | 
						|
	  system uptime when signalled */
 | 
						|
      if (timeout->QuadPart < 0LL)
 | 
						|
	timeout->QuadPart = tbi.SignalState ? 0LL : tbi.TimeRemaining.QuadPart;
 | 
						|
      NtCancelTimer (_my_tls.locals.cw_timer, NULL);
 | 
						|
    }
 | 
						|
 | 
						|
  if (res == WAIT_CANCELED && is_cw_cancel_self)
 | 
						|
    pthread::static_cancel_self ();
 | 
						|
 | 
						|
  return res;
 | 
						|
}
 |