Пример #1
0
static void CALLBACK
ptw32_cancel_callback (DWORD unused)
{
  ptw32_throw (PTW32_EPS_CANCEL);

  /* Never reached */
}
Пример #2
0
static INLINE void
ptw32_cancel_self(void)
{
  ptw32_throw(PTW32_EPS_CANCEL);

  /* Never reached */
}
Пример #3
0
static void CALLBACK
ptw32_cancel_callback (ULONG_PTR unused)
{
    ptw32_throw (PTW32_EPS_CANCEL);


}
Пример #4
0
static void
ptw32_cancel_self (void)
{
    ptw32_throw (PTW32_EPS_CANCEL);


}
int
pthread_setcanceltype (int type, int *oldtype)
{
  ptw32_mcs_local_node_t stateLock;
  int result = 0;
  pthread_t self = pthread_self ();
  ptw32_thread_t * sp = (ptw32_thread_t *) self.p;

  if (sp == NULL
      || (type != PTHREAD_CANCEL_DEFERRED
	  && type != PTHREAD_CANCEL_ASYNCHRONOUS))
    {
      return EINVAL;
    }

  ptw32_mcs_lock_acquire (&sp->stateLock, &stateLock);

  if (oldtype != NULL)
    {
      *oldtype = sp->cancelType;
    }

  sp->cancelType = type;

  if (sp->cancelState == PTHREAD_CANCEL_ENABLE
      && type == PTHREAD_CANCEL_ASYNCHRONOUS
      && WaitForSingleObject (sp->cancelEvent, 0) == WAIT_OBJECT_0)
    {
      sp->state = PThreadStateCanceling;
      sp->cancelState = PTHREAD_CANCEL_DISABLE;
      ResetEvent (sp->cancelEvent);
      ptw32_mcs_lock_release (&stateLock);
      ptw32_throw (PTW32_EPS_CANCEL);

      
    }

  ptw32_mcs_lock_release (&stateLock);

  return (result);

}				
Пример #6
0
int
pthread_cancel (pthread_t thread)
     /*
      * ------------------------------------------------------
      * DOCPUBLIC
      *      This function requests cancellation of 'thread'.
      *
      * PARAMETERS
      *      thread
      *              reference to an instance of pthread_t
      *
      *
      * DESCRIPTION
      *      This function requests cancellation of 'thread'.
      *      NOTE: cancellation is asynchronous; use pthread_join to
      *                wait for termination of 'thread' if necessary.
      *
      * RESULTS
      *              0               successfully requested cancellation,
      *              ESRCH           no thread found corresponding to 'thread',
      *              ENOMEM          implicit self thread create failed.
      * ------------------------------------------------------
      */
{
  int result;
  int cancel_self;
  pthread_t self;
  ptw32_thread_t * tp;

  result = pthread_kill (thread, 0);

  if (0 != result)
    {
      return result;
    }

  if ((self = pthread_self ()).p == NULL)
    {
      return ENOMEM;
    };

  /*
   * FIXME!!
   *
   * Can a thread cancel itself?
   *
   * The standard doesn't
   * specify an error to be returned if the target
   * thread is itself.
   *
   * If it may, then we need to ensure that a thread can't
   * deadlock itself trying to cancel itself asyncronously
   * (pthread_cancel is required to be an async-cancel
   * safe function).
   */
  cancel_self = pthread_equal (thread, self);

  tp = (ptw32_thread_t *) thread.p;

  /*
   * Lock for async-cancel safety.
   */
  (void) pthread_mutex_lock (&tp->cancelLock);

  if (tp->cancelType == PTHREAD_CANCEL_ASYNCHRONOUS
      && tp->cancelState == PTHREAD_CANCEL_ENABLE
      && tp->state < PThreadStateCanceling)
    {
      if (cancel_self)
	{
	  tp->state = PThreadStateCanceling;
	  tp->cancelState = PTHREAD_CANCEL_DISABLE;

	  (void) pthread_mutex_unlock (&tp->cancelLock);
	  ptw32_throw (PTW32_EPS_CANCEL);

	  /* Never reached */
	}
      else
	{
	  HANDLE threadH = tp->threadH;

	  SuspendThread (threadH);

	  if (WaitForSingleObject (threadH, 0) == WAIT_TIMEOUT)
	    {
	      tp->state = PThreadStateCanceling;
	      tp->cancelState = PTHREAD_CANCEL_DISABLE;
	      /*
	       * If alertdrv and QueueUserAPCEx is available then the following
	       * will result in a call to QueueUserAPCEx with the args given, otherwise
	       * this will result in a call to ptw32_RegisterCancelation and only
	       * the threadH arg will be used.
	       */
	      ptw32_register_cancelation (ptw32_cancel_callback, threadH, 0);
	      (void) pthread_mutex_unlock (&tp->cancelLock);
	      //ResumeThread (threadH);
	    }
	}
    }
  else
    {
      /*
       * Set for deferred cancellation.
       */
      if (tp->state < PThreadStateCancelPending)
	{
	  tp->state = PThreadStateCancelPending;
	  if (!SetEvent (tp->cancelEvent))
	    {
	      result = ESRCH;
	    }
	}
      else if (tp->state >= PThreadStateCanceling)
	{
	  result = ESRCH;
	}

      (void) pthread_mutex_unlock (&tp->cancelLock);
    }
  return (result);
}
Пример #7
0
int
pthread_cancel (pthread_t thread)
     /*
      * ------------------------------------------------------
      * DOCPUBLIC
      *      This function requests cancellation of 'thread'.
      *
      * PARAMETERS
      *      thread
      *              reference to an instance of pthread_t
      *
      *
      * DESCRIPTION
      *      This function requests cancellation of 'thread'.
      *      NOTE: cancellation is asynchronous; use pthread_join to
      *                wait for termination of 'thread' if necessary.
      *
      * RESULTS
      *              0               successfully requested cancellation,
      *              ESRCH           no thread found corresponding to 'thread',
      *              ENOMEM          implicit self thread create failed.
      * ------------------------------------------------------
      */
{
  int result;
  int cancel_self;
  pthread_t self;

  if (thread == NULL )
    {
      return ESRCH;
    }

  result = 0;
  if ((self = pthread_self()) == NULL)
    {
      return ENOMEM;
    };

  /*
   * FIXME!!
   *
   * Can a thread cancel itself?
   *
   * The standard doesn't
   * specify an error to be returned if the target
   * thread is itself.
   *
   * If it may, then we need to ensure that a thread can't
   * deadlock itself trying to cancel itself asyncronously
   * (pthread_cancel is required to be an async-cancel
   * safe function).
   */
  cancel_self = pthread_equal(thread, self);

  /*
   * Lock for async-cancel safety.
   */
  (void) pthread_mutex_lock(&thread->cancelLock);

  if (thread->cancelType == PTHREAD_CANCEL_ASYNCHRONOUS
      && thread->cancelState == PTHREAD_CANCEL_ENABLE
      && thread->state < PThreadStateCanceling )
    {
      if (cancel_self)
        {
          thread->state = PThreadStateCanceling;
          thread->cancelState = PTHREAD_CANCEL_DISABLE;

          (void) pthread_mutex_unlock(&thread->cancelLock);
          ptw32_throw(PTW32_EPS_CANCEL);

          /* Never reached */
        }
      else
        {
          HANDLE threadH = thread->threadH;

          SuspendThread(threadH);

          if (WaitForSingleObject(threadH, 0) == WAIT_TIMEOUT )
            {
              CONTEXT context;

              thread->state = PThreadStateCanceling;
              thread->cancelState = PTHREAD_CANCEL_DISABLE;
              context.ContextFlags = CONTEXT_CONTROL;
              GetThreadContext(threadH, &context);
              PTW32_PROGCTR(context) = (DWORD) ptw32_cancel_self;
              SetThreadContext(threadH, &context);
              (void) pthread_mutex_unlock(&thread->cancelLock);
              ResumeThread(threadH);
            }
        }
    }
  else
    {
      /*
       * Set for deferred cancellation.
       */
      if ( thread->state >= PThreadStateCanceling
           || !SetEvent (thread->cancelEvent))
        {
          result = ESRCH;
        }

      (void) pthread_mutex_unlock(&thread->cancelLock);
    }

  return (result);
}
Пример #8
0
void
pthread_exit (void *value_ptr)
     /*
      * ------------------------------------------------------
      * DOCPUBLIC
      *      This function terminates the calling thread, returning
      *      the value 'value_ptr' to any joining thread.
      *
      * PARAMETERS
      *      value_ptr
      *              a generic data value (i.e. not the address of a value)
      *
      *
      * DESCRIPTION
      *      This function terminates the calling thread, returning
      *      the value 'value_ptr' to any joining thread.
      *      NOTE: thread should be joinable.
      *
      * RESULTS
      *              N/A
      *
      * ------------------------------------------------------
      */
{
  ptw32_thread_t * sp;

  /*
   * Don't use pthread_self() to avoid creating an implicit POSIX thread handle
   * unnecessarily.
   */
  sp = (ptw32_thread_t *) pthread_getspecific (ptw32_selfThreadKey);

#ifdef _UWIN
  if (--pthread_count <= 0)
    exit ((int) value_ptr);
#endif

  if (NULL == sp)
    {
      /*
       * A POSIX thread handle was never created. I.e. this is a
       * Win32 thread that has never called a pthreads-win32 routine that
       * required a POSIX handle.
       *
       * Implicit POSIX handles are cleaned up in ptw32_throw() now.
       */

#if ! defined (__MINGW32__) || defined (__MSVCRT__)  || defined (__DMC__)
      _endthreadex ((unsigned) value_ptr);
#else
      _endthread ();
#endif

      /* Never reached */
    }

  sp->exitStatus = value_ptr;

  ptw32_throw (PTW32_EPS_EXIT);

  /* Never reached. */

}
Пример #9
0
static INLINE int
ptw32_cancelable_wait (HANDLE waitHandle, DWORD timeout)
     /*
      * -------------------------------------------------------------------
      * This provides an extra hook into the pthread_cancel
      * mechanism that will allow you to wait on a Windows handle and make it a
      * cancellation point. This function blocks until the given WIN32 handle is
      * signaled or pthread_cancel has been called. It is implemented using
      * WaitForMultipleObjects on 'waitHandle' and a manually reset WIN32
      * event used to implement pthread_cancel.
      * 
      * Given this hook it would be possible to implement more of the cancellation
      * points.
      * -------------------------------------------------------------------
      */
{
  int result;
  pthread_t self;
  ptw32_thread_t * sp;
  HANDLE handles[2];
  DWORD nHandles = 1;
  DWORD status;

  handles[0] = waitHandle;

  self = pthread_self();
  sp = (ptw32_thread_t *) to_internal(self).p;

  if (sp != NULL)
    {
      /*
       * Get cancelEvent handle
       */
      if (sp->cancelState == PTHREAD_CANCEL_ENABLE)
	{

	  if ((handles[1] = sp->cancelEvent) != NULL)
	    {
	      nHandles++;
	    }
	}
    }
  else
    {
      handles[1] = NULL;
    }

  status = WaitForMultipleObjects (nHandles, handles, PTW32_FALSE, timeout);

  switch (status - WAIT_OBJECT_0)
    {
    case 0:
      /*
       * Got the handle.
       * In the event that both handles are signalled, the smallest index
       * value (us) is returned. As it has been arranged, this ensures that
       * we don't drop a signal that we should act on (i.e. semaphore,
       * mutex, or condition variable etc).
       */
      result = 0;
      break;

    case 1:
      /*
       * Got cancel request.
       * In the event that both handles are signaled, the cancel will
       * be ignored (see case 0 comment).
       */
      ResetEvent (handles[1]);

      if (sp != NULL)
	{
          ptw32_mcs_local_node_t stateLock;
	  /*
	   * Should handle POSIX and implicit POSIX threads..
	   * Make sure we haven't been async-canceled in the meantime.
	   */
	  ptw32_mcs_lock_acquire (&sp->stateLock, &stateLock);
	  if (sp->state < PThreadStateCanceling)
	    {
	      sp->state = PThreadStateCanceling;
	      sp->cancelState = PTHREAD_CANCEL_DISABLE;
	      ptw32_mcs_lock_release (&stateLock);
	      ptw32_throw (PTW32_EPS_CANCEL);

	      /* Never reached */
	    }
	  ptw32_mcs_lock_release (&stateLock);
	}

      /* Should never get to here. */
      result = EINVAL;
      break;

    default:
      if (status == WAIT_TIMEOUT)
	{
	  result = ETIMEDOUT;
	}
      else
	{
	  result = EINVAL;
	}
      break;
    }

  return (result);

}				/* CancelableWait */
Пример #10
0
/*
 * pthread_delay_np
 *
 * DESCRIPTION
 *
 *       This routine causes a thread to delay execution for a specific period of time.
 *       This period ends at the current time plus the specified interval. The routine
 *       will not return before the end of the period is reached, but may return an
 *       arbitrary amount of time after the period has gone by. This can be due to
 *       system load, thread priorities, and system timer granularity.
 *
 *       Specifying an interval of zero (0) seconds and zero (0) nanoseconds is
 *       allowed and can be used to force the thread to give up the processor or to
 *       deliver a pending cancelation request.
 *
 *       The timespec structure contains the following two fields:
 *
 *            tv_sec is an integer number of seconds.
 *            tv_nsec is an integer number of nanoseconds.
 *
 *  Return Values
 *
 *  If an error condition occurs, this routine returns an integer value indicating
 *  the type of error. Possible return values are as follows:
 *
 *  0
 *           Successful completion.
 *  [EINVAL]
 *           The value specified by interval is invalid.
 *
 * Example
 *
 * The following code segment would wait for 5 and 1/2 seconds
 *
 *  struct timespec tsWait;
 *  int      intRC;
 *
 *  tsWait.tv_sec  = 5;
 *  tsWait.tv_nsec = 500000000L;
 *  intRC = pthread_delay_np(&tsWait);
 */
int
pthread_delay_np (struct timespec *interval)
{
  DWORD wait_time;
  DWORD secs_in_millisecs;
  DWORD millisecs;
  DWORD status;
  pthread_t self;
  ptw32_thread_t * sp;

  if (interval == NULL)
    {
      return EINVAL;
    }

  if (interval->tv_sec == 0L && interval->tv_nsec == 0L)
    {
      pthread_testcancel ();
      Sleep (0);
      pthread_testcancel ();
      return (0);
    }

  /* convert secs to millisecs */
  secs_in_millisecs = interval->tv_sec * 1000L;

  /* convert nanosecs to millisecs (rounding up) */
  millisecs = (interval->tv_nsec + 999999L) / 1000000L;

#if defined(__WATCOMC__)
#pragma disable_message (124)
#endif

  /*
   * Most compilers will issue a warning 'comparison always 0'
   * because the variable type is unsigned, but we need to keep this
   * for some reason I can't recall now.
   */
  if (0 > (wait_time = secs_in_millisecs + millisecs))
    {
      return EINVAL;
    }

#if defined(__WATCOMC__)
#pragma enable_message (124)
#endif

  if (NULL == (self = pthread_self ()).p)
    {
      return ENOMEM;
    }

  sp = (ptw32_thread_t *) self.p;

  if (sp->cancelState == PTHREAD_CANCEL_ENABLE)
    {
      /*
       * Async cancelation won't catch us until wait_time is up.
       * Deferred cancelation will cancel us immediately.
       */
      if (WAIT_OBJECT_0 ==
	  (status = WaitForSingleObject (sp->cancelEvent, wait_time)))
	{
	  /*
	   * Canceling!
	   */
	  (void) pthread_mutex_lock (&sp->cancelLock);
	  if (sp->state < PThreadStateCanceling)
	    {
	      sp->state = PThreadStateCanceling;
	      sp->cancelState = PTHREAD_CANCEL_DISABLE;
	      (void) pthread_mutex_unlock (&sp->cancelLock);

	      ptw32_throw (PTW32_EPS_CANCEL);
	    }

	  (void) pthread_mutex_unlock (&sp->cancelLock);
	  return ESRCH;
	}
      else if (status != WAIT_TIMEOUT)
	{
	  return EINVAL;
	}
    }
  else
    {
      Sleep (wait_time);
    }

  return (0);
}
Пример #11
0
void
pthread_testcancel (void)
     /*
      * ------------------------------------------------------
      * DOCPUBLIC
      *      This function creates a deferred cancellation point
      *      in the calling thread. The call has no effect if the
      *      current cancelability state is
      *              PTHREAD_CANCEL_DISABLE
      *
      * PARAMETERS
      *      N/A
      *
      *
      * DESCRIPTION
      *      This function creates a deferred cancellation point
      *      in the calling thread. The call has no effect if the
      *      current cancelability state is
      *              PTHREAD_CANCEL_DISABLE
      *
      *      NOTES:
      *      1)      Cancellation is asynchronous. Use pthread_join
      *              to wait for termination of thread if necessary
      *
      * RESULTS
      *              N/A
      *
      * ------------------------------------------------------
      */
{
  pthread_t self = pthread_self ();
  ptw32_thread_t * sp = (ptw32_thread_t *) self.p;

  if (sp == NULL)
    {
      return;
    }

  /*
   * Pthread_cancel() will have set sp->state to PThreadStateCancelPending
   * and set an event, so no need to enter kernel space if
   * sp->state != PThreadStateCancelPending - that only slows us down.
   */
  if (sp->state != PThreadStateCancelPending)
    {
      return;
    }

  (void) pthread_mutex_lock (&sp->cancelLock);

  if (sp->cancelState != PTHREAD_CANCEL_DISABLE)
    {
      ResetEvent(sp->cancelEvent);
      sp->state = PThreadStateCanceling;
      sp->cancelState = PTHREAD_CANCEL_DISABLE;
      (void) pthread_mutex_unlock (&sp->cancelLock);
      ptw32_throw (PTW32_EPS_CANCEL);
      /* Never returns here */
    }

  (void) pthread_mutex_unlock (&sp->cancelLock);
}				/* pthread_testcancel */
int
pthread_setcancelstate (int state, int *oldstate)
     /*
      * ------------------------------------------------------
      * DOCPUBLIC
      *      This function atomically sets the calling thread's
      *      cancelability state to 'state' and returns the previous
      *      cancelability state at the location referenced by
      *      'oldstate'
      *
      * PARAMETERS
      *      state,
      *      oldstate
      *              PTHREAD_CANCEL_ENABLE
      *                      cancellation is enabled,
      *
      *              PTHREAD_CANCEL_DISABLE
      *                      cancellation is disabled
      *
      *
      * DESCRIPTION
      *      This function atomically sets the calling thread's
      *      cancelability state to 'state' and returns the previous
      *      cancelability state at the location referenced by
      *      'oldstate'.
      *
      *      NOTES:
      *      1)      Use to disable cancellation around 'atomic' code that
      *              includes cancellation points
      *
      * COMPATIBILITY ADDITIONS
      *      If 'oldstate' is NULL then the previous state is not returned
      *      but the function still succeeds. (Solaris)
      *
      * RESULTS
      *              0               successfully set cancelability type,
      *              EINVAL          'state' is invalid
      *
      * ------------------------------------------------------
      */
{
  ptw32_mcs_local_node_t stateLock;
  int result = 0;
  pthread_t self = pthread_self ();
  ptw32_thread_t * sp = (ptw32_thread_t *) self.p;

  if (sp == NULL
      || (state != PTHREAD_CANCEL_ENABLE && state != PTHREAD_CANCEL_DISABLE))
    {
      return EINVAL;
    }

  /*
   * Lock for async-cancel safety.
   */
  ptw32_mcs_lock_acquire (&sp->stateLock, &stateLock);

  if (oldstate != NULL)
    {
      *oldstate = sp->cancelState;
    }

  sp->cancelState = state;

  /*
   * Check if there is a pending asynchronous cancel
   */
  if (state == PTHREAD_CANCEL_ENABLE
      && sp->cancelType == PTHREAD_CANCEL_ASYNCHRONOUS
      && WaitForSingleObject (sp->cancelEvent, 0) == WAIT_OBJECT_0)
    {
      sp->state = PThreadStateCanceling;
      sp->cancelState = PTHREAD_CANCEL_DISABLE;
      ResetEvent (sp->cancelEvent);
      ptw32_mcs_lock_release (&stateLock);
      ptw32_throw (PTW32_EPS_CANCEL);

      /* Never reached */
    }

  ptw32_mcs_lock_release (&stateLock);

  return (result);

}				/* pthread_setcancelstate */
Пример #13
0
int
pthread_cancel (pthread_t thread)
{
    int result;
    int cancel_self;
    pthread_t self;
    ptw32_thread_t * tp;
    ptw32_mcs_local_node_t stateLock;

    result = pthread_kill (thread, 0);

    if (0 != result)
    {
        return result;
    }

    if ((self = pthread_self ()).p == NULL)
    {
        return ENOMEM;
    };

    cancel_self = pthread_equal (thread, self);

    tp = (ptw32_thread_t *) thread.p;

    ptw32_mcs_lock_acquire (&tp->stateLock, &stateLock);

    if (tp->cancelType == PTHREAD_CANCEL_ASYNCHRONOUS
            && tp->cancelState == PTHREAD_CANCEL_ENABLE
            && tp->state < PThreadStateCanceling)
    {
        if (cancel_self)
        {
            tp->state = PThreadStateCanceling;
            tp->cancelState = PTHREAD_CANCEL_DISABLE;

            ptw32_mcs_lock_release (&stateLock);
            ptw32_throw (PTW32_EPS_CANCEL);


        }
        else
        {
            HANDLE threadH = tp->threadH;

            SuspendThread (threadH);

            if (WaitForSingleObject (threadH, 0) == WAIT_TIMEOUT)
            {
                tp->state = PThreadStateCanceling;
                tp->cancelState = PTHREAD_CANCEL_DISABLE;
                ptw32_register_cancelation ((PAPCFUNC)ptw32_cancel_callback, threadH, 0);
                ptw32_mcs_lock_release (&stateLock);
                ResumeThread (threadH);
            }
        }
    }
    else
    {
        if (tp->state < PThreadStateCancelPending)
        {
            tp->state = PThreadStateCancelPending;
            if (!SetEvent (tp->cancelEvent))
            {
                result = ESRCH;
            }
        }
        else if (tp->state >= PThreadStateCanceling)
        {
            result = ESRCH;
        }

        ptw32_mcs_lock_release (&stateLock);
    }

    return (result);
}
int
pthread_setcanceltype (int type, int *oldtype)
     /*
      * ------------------------------------------------------
      * DOCPUBLIC
      *      This function atomically sets the calling thread's
      *      cancelability type to 'type' and returns the previous
      *      cancelability type at the location referenced by
      *      'oldtype'
      *
      * PARAMETERS
      *      type,
      *      oldtype
      *              PTHREAD_CANCEL_DEFERRED
      *                      only deferred cancelation is allowed,
      *
      *              PTHREAD_CANCEL_ASYNCHRONOUS
      *                      Asynchronous cancellation is allowed
      *
      *
      * DESCRIPTION
      *      This function atomically sets the calling thread's
      *      cancelability type to 'type' and returns the previous
      *      cancelability type at the location referenced by
      *      'oldtype'
      *
      *      NOTES:
      *      1)      Use with caution; most code is not safe for use
      *              with asynchronous cancelability.
      *
      * COMPATIBILITY ADDITIONS
      *      If 'oldtype' is NULL then the previous type is not returned
      *      but the function still succeeds. (Solaris)
      *
      * RESULTS
      *              0               successfully set cancelability type,
      *              EINVAL          'type' is invalid
      *
      * ------------------------------------------------------
      */
{
  ptw32_mcs_local_node_t stateLock;
  int result = 0;
  pthread_t self = pthread_self ();
  ptw32_thread_t * sp = (ptw32_thread_t *) self.p;

  if (sp == NULL
      || (type != PTHREAD_CANCEL_DEFERRED
	  && type != PTHREAD_CANCEL_ASYNCHRONOUS))
    {
      return EINVAL;
    }

  /*
   * Lock for async-cancel safety.
   */
  ptw32_mcs_lock_acquire (&sp->stateLock, &stateLock);

  if (oldtype != NULL)
    {
      *oldtype = sp->cancelType;
    }

  sp->cancelType = type;

  /*
   * Check if there is a pending asynchronous cancel
   */
  if (sp->cancelState == PTHREAD_CANCEL_ENABLE
      && type == PTHREAD_CANCEL_ASYNCHRONOUS
      && WaitForSingleObject (sp->cancelEvent, 0) == WAIT_OBJECT_0)
    {
      sp->state = PThreadStateCanceling;
      sp->cancelState = PTHREAD_CANCEL_DISABLE;
      ResetEvent (sp->cancelEvent);
      ptw32_mcs_lock_release (&stateLock);
      ptw32_throw (PTW32_EPS_CANCEL);

      /* Never reached */
    }

  ptw32_mcs_lock_release (&stateLock);

  return (result);

}				/* pthread_setcanceltype */
Пример #15
0
int
pthread_delay_np (struct timespec *interval)
{
  DWORD wait_time;
  DWORD secs_in_millisecs;
  DWORD millisecs;
  DWORD status;
  pthread_t self;
  ptw32_thread_t * sp;

  if (interval == NULL)
    {
      return EINVAL;
    }

  if (interval->tv_sec == 0L && interval->tv_nsec == 0L)
    {
      pthread_testcancel ();
      Sleep (0);
      pthread_testcancel ();
      return (0);
    }

  
  secs_in_millisecs = (DWORD)interval->tv_sec * 1000L;

  
  millisecs = (interval->tv_nsec + 999999L) / 1000000L;

#if defined(__WATCOMC__)
#pragma disable_message (124)
#endif

  if (0 > (wait_time = secs_in_millisecs + millisecs))
    {
      return EINVAL;
    }

#if defined(__WATCOMC__)
#pragma enable_message (124)
#endif

  if (NULL == (self = pthread_self ()).p)
    {
      return ENOMEM;
    }

  sp = (ptw32_thread_t *) self.p;

  if (sp->cancelState == PTHREAD_CANCEL_ENABLE)
    {
      if (WAIT_OBJECT_0 ==
	  (status = WaitForSingleObject (sp->cancelEvent, wait_time)))
	{
          ptw32_mcs_local_node_t stateLock;
	  ptw32_mcs_lock_acquire (&sp->stateLock, &stateLock);
	  if (sp->state < PThreadStateCanceling)
	    {
	      sp->state = PThreadStateCanceling;
	      sp->cancelState = PTHREAD_CANCEL_DISABLE;
	      ptw32_mcs_lock_release (&stateLock);

	      ptw32_throw (PTW32_EPS_CANCEL);
	    }

	  ptw32_mcs_lock_release (&stateLock);
	  return ESRCH;
	}
      else if (status != WAIT_TIMEOUT)
	{
	  return EINVAL;
	}
    }
  else
    {
      Sleep (wait_time);
    }

  return (0);
}