1/*
2 * w32_CancelableWait.c
3 *
4 * Description:
5 * This translation unit implements miscellaneous thread functions.
6 *
7 * --------------------------------------------------------------------------
8 *
9 *      Pthreads-win32 - POSIX Threads Library for Win32
10 *      Copyright(C) 1998 John E. Bossom
11 *      Copyright(C) 1999,2005 Pthreads-win32 contributors
12 *
13 *      Contact Email: rpj@callisto.canberra.edu.au
14 *
15 *      The current list of contributors is contained
16 *      in the file CONTRIBUTORS included with the source
17 *      code distribution. The list can also be seen at the
18 *      following World Wide Web location:
19 *      http://sources.redhat.com/pthreads-win32/contributors.html
20 *
21 *      This library is free software; you can redistribute it and/or
22 *      modify it under the terms of the GNU Lesser General Public
23 *      License as published by the Free Software Foundation; either
24 *      version 2 of the License, or (at your option) any later version.
25 *
26 *      This library is distributed in the hope that it will be useful,
27 *      but WITHOUT ANY WARRANTY; without even the implied warranty of
28 *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
29 *      Lesser General Public License for more details.
30 *
31 *      You should have received a copy of the GNU Lesser General Public
32 *      License along with this library in the file COPYING.LIB;
33 *      if not, write to the Free Software Foundation, Inc.,
34 *      59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
35 */
36
37#include "pthread.h"
38#include "implement.h"
39
40
41static INLINE int
42ptw32_cancelable_wait (HANDLE waitHandle, DWORD timeout)
43     /*
44      * -------------------------------------------------------------------
45      * This provides an extra hook into the pthread_cancel
46      * mechanism that will allow you to wait on a Windows handle and make it a
47      * cancellation point. This function blocks until the given WIN32 handle is
48      * signaled or pthread_cancel has been called. It is implemented using
49      * WaitForMultipleObjects on 'waitHandle' and a manually reset WIN32
50      * event used to implement pthread_cancel.
51      *
52      * Given this hook it would be possible to implement more of the cancellation
53      * points.
54      * -------------------------------------------------------------------
55      */
56{
57  int result;
58  pthread_t self;
59  ptw32_thread_t * sp;
60  HANDLE handles[2];
61  DWORD nHandles = 1;
62  DWORD status;
63
64  handles[0] = waitHandle;
65
66  self = pthread_self();
67  sp = (ptw32_thread_t *) self.p;
68
69  if (sp != NULL)
70    {
71      /*
72       * Get cancelEvent handle
73       */
74      if (sp->cancelState == PTHREAD_CANCEL_ENABLE)
75	{
76
77	  if ((handles[1] = sp->cancelEvent) != NULL)
78	    {
79	      nHandles++;
80	    }
81	}
82    }
83  else
84    {
85      handles[1] = NULL;
86    }
87
88  status = WaitForMultipleObjects (nHandles, handles, PTW32_FALSE, timeout);
89
90  switch (status - WAIT_OBJECT_0)
91    {
92    case 0:
93      /*
94       * Got the handle.
95       * In the event that both handles are signalled, the smallest index
96       * value (us) is returned. As it has been arranged, this ensures that
97       * we don't drop a signal that we should act on (i.e. semaphore,
98       * mutex, or condition variable etc).
99       */
100      result = 0;
101      break;
102
103    case 1:
104      /*
105       * Got cancel request.
106       * In the event that both handles are signaled, the cancel will
107       * be ignored (see case 0 comment).
108       */
109      ResetEvent (handles[1]);
110
111      if (sp != NULL)
112	{
113          ptw32_mcs_local_node_t stateLock;
114	  /*
115	   * Should handle POSIX and implicit POSIX threads..
116	   * Make sure we haven't been async-canceled in the meantime.
117	   */
118	  ptw32_mcs_lock_acquire (&sp->stateLock, &stateLock);
119	  if (sp->state < PThreadStateCanceling)
120	    {
121	      sp->state = PThreadStateCanceling;
122	      sp->cancelState = PTHREAD_CANCEL_DISABLE;
123	      ptw32_mcs_lock_release (&stateLock);
124	      ptw32_throw (PTW32_EPS_CANCEL);
125
126	      /* Never reached */
127	    }
128	  ptw32_mcs_lock_release (&stateLock);
129	}
130
131      /* Should never get to here. */
132      result = EINVAL;
133      break;
134
135    default:
136      if (status == WAIT_TIMEOUT)
137	{
138	  result = ETIMEDOUT;
139	}
140      else
141	{
142	  result = EINVAL;
143	}
144      break;
145    }
146
147  return (result);
148
149}				/* CancelableWait */
150
151int
152pthreadCancelableWait (HANDLE waitHandle)
153{
154  return (ptw32_cancelable_wait (waitHandle, INFINITE));
155}
156
157int
158pthreadCancelableTimedWait (HANDLE waitHandle, DWORD timeout)
159{
160  return (ptw32_cancelable_wait (waitHandle, timeout));
161}
162