- add sources.
[platform/framework/web/crosswalk.git] / src / native_client_sdk / src / libraries / third_party / pthreads-win32 / pthread_cancel.c
1 /*
2  * pthread_cancel.c
3  *
4  * Description:
5  * POSIX thread functions related to thread cancellation.
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 #include "context.h"
40
41 static void
42 ptw32_cancel_self (void)
43 {
44   ptw32_throw (PTW32_EPS_CANCEL);
45
46   /* Never reached */
47 }
48
49 static void CALLBACK
50 ptw32_cancel_callback (ULONG_PTR unused)
51 {
52   ptw32_throw (PTW32_EPS_CANCEL);
53
54   /* Never reached */
55 }
56
57 /*
58  * ptw32_RegisterCancelation() -
59  * Must have args of same type as QueueUserAPCEx because this function
60  * is a substitute for QueueUserAPCEx if it's not available.
61  */
62 DWORD
63 ptw32_RegisterCancelation (PAPCFUNC unused1, HANDLE threadH, DWORD unused2)
64 {
65   CONTEXT context;
66
67   context.ContextFlags = CONTEXT_CONTROL;
68   GetThreadContext (threadH, &context);
69   PTW32_PROGCTR (context) = (DWORD_PTR) ptw32_cancel_self;
70   SetThreadContext (threadH, &context);
71   return 0;
72 }
73
74 int
75 pthread_cancel (pthread_t thread)
76      /*
77       * ------------------------------------------------------
78       * DOCPUBLIC
79       *      This function requests cancellation of 'thread'.
80       *
81       * PARAMETERS
82       *      thread
83       *              reference to an instance of pthread_t
84       *
85       *
86       * DESCRIPTION
87       *      This function requests cancellation of 'thread'.
88       *      NOTE: cancellation is asynchronous; use pthread_join to
89       *                wait for termination of 'thread' if necessary.
90       *
91       * RESULTS
92       *              0               successfully requested cancellation,
93       *              ESRCH           no thread found corresponding to 'thread',
94       *              ENOMEM          implicit self thread create failed.
95       * ------------------------------------------------------
96       */
97 {
98   int result;
99   int cancel_self;
100   pthread_t self;
101   ptw32_thread_t * tp;
102   ptw32_mcs_local_node_t stateLock;
103
104   result = pthread_kill (thread, 0);
105
106   if (0 != result)
107     {
108       return result;
109     }
110
111   if ((self = pthread_self ()).p == NULL)
112     {
113       return ENOMEM;
114     };
115
116   /*
117    * For self cancellation we need to ensure that a thread can't
118    * deadlock itself trying to cancel itself asynchronously
119    * (pthread_cancel is required to be an async-cancel
120    * safe function).
121    */
122   cancel_self = pthread_equal (thread, self);
123
124   tp = (ptw32_thread_t *) thread.p;
125
126   /*
127    * Lock for async-cancel safety.
128    */
129   ptw32_mcs_lock_acquire (&tp->stateLock, &stateLock);
130
131   if (tp->cancelType == PTHREAD_CANCEL_ASYNCHRONOUS
132       && tp->cancelState == PTHREAD_CANCEL_ENABLE
133       && tp->state < PThreadStateCanceling)
134     {
135       if (cancel_self)
136         {
137           tp->state = PThreadStateCanceling;
138           tp->cancelState = PTHREAD_CANCEL_DISABLE;
139
140           ptw32_mcs_lock_release (&stateLock);
141           ptw32_throw (PTW32_EPS_CANCEL);
142
143           /* Never reached */
144         }
145       else
146         {
147           HANDLE threadH = tp->threadH;
148
149           SuspendThread (threadH);
150
151           if (WaitForSingleObject (threadH, 0) == WAIT_TIMEOUT)
152             {
153               tp->state = PThreadStateCanceling;
154               tp->cancelState = PTHREAD_CANCEL_DISABLE;
155               /*
156                * If alertdrv and QueueUserAPCEx is available then the following
157                * will result in a call to QueueUserAPCEx with the args given, otherwise
158                * this will result in a call to ptw32_RegisterCancelation and only
159                * the threadH arg will be used.
160                */
161               ptw32_register_cancelation ((PAPCFUNC)ptw32_cancel_callback, threadH, 0);
162               ptw32_mcs_lock_release (&stateLock);
163               ResumeThread (threadH);
164             }
165         }
166     }
167   else
168     {
169       /*
170        * Set for deferred cancellation.
171        */
172       if (tp->state < PThreadStateCancelPending)
173         {
174           tp->state = PThreadStateCancelPending;
175           if (!SetEvent (tp->cancelEvent))
176             {
177               result = ESRCH;
178             }
179         }
180       else if (tp->state >= PThreadStateCanceling)
181         {
182           result = ESRCH;
183         }
184
185       ptw32_mcs_lock_release (&stateLock);
186     }
187
188   return (result);
189 }