OSDN Git Service

* globals.cc (enum exit_states::ES_GLOBAL_DTORS): Delete.
[pf3gnuchains/pf3gnuchains4x.git] / winsup / cygwin / cygthread.cc
1 /* cygthread.cc
2
3    Copyright 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2008, 2009
4    Red Hat, Inc.
5
6 This software is a copyrighted work licensed under the terms of the
7 Cygwin license.  Please consult the file "CYGWIN_LICENSE" for
8 details. */
9
10 #include "winsup.h"
11 #include "miscfuncs.h"
12 #include <stdlib.h>
13 #include "sigproc.h"
14 #include "cygtls.h"
15
16 #undef CloseHandle
17
18 static cygthread NO_COPY threads[32];
19 #define NTHREADS (sizeof (threads) / sizeof (threads[0]))
20
21 DWORD NO_COPY cygthread::main_thread_id;
22 bool NO_COPY cygthread::exiting;
23
24 void
25 cygthread::callfunc (bool issimplestub)
26 {
27   void *pass_arg;
28   if (arg == cygself)
29     pass_arg = this;
30   else if (!arglen)
31     pass_arg = arg;
32   else
33     {
34       if (issimplestub)
35         ev = CreateEvent (&sec_none_nih, TRUE, FALSE, NULL);
36       pass_arg = alloca (arglen);
37       memcpy (pass_arg, arg, arglen);
38       SetEvent (ev);
39     }
40   if (issimplestub)
41     {
42       /* Wait for main thread to assign 'h' */
43       while (!h)
44         low_priority_sleep (0);
45       if (ev)
46         CloseHandle (ev);
47       ev = h;
48     }
49   /* Cygwin threads should not call ExitThread directly */
50   func (pass_arg);
51   /* ...so the above should always return */
52 }
53
54 /* Initial stub called by cygthread constructor. Performs initial
55    per-thread initialization and loops waiting for another thread function
56    to execute.  */
57 DWORD WINAPI
58 cygthread::stub (VOID *arg)
59 {
60   cygthread *info = (cygthread *) arg;
61   _my_tls._ctinfo = info;
62   if (info->arg == cygself)
63     {
64       if (info->ev)
65         {
66           CloseHandle (info->ev);
67           CloseHandle (info->thread_sync);
68         }
69       info->ev = info->thread_sync = info->stack_ptr = NULL;
70     }
71   else
72     {
73       info->stack_ptr = &arg;
74       debug_printf ("thread '%s', id %p, stack_ptr %p", info->name (), info->id, info->stack_ptr);
75       if (!info->ev)
76         {
77           info->ev = CreateEvent (&sec_none_nih, TRUE, FALSE, NULL);
78           info->thread_sync = CreateEvent (&sec_none_nih, FALSE, FALSE, NULL);
79         }
80     }
81
82   while (1)
83     {
84       if (!info->__name)
85 #ifdef DEBUGGING
86         system_printf ("erroneous thread activation, name is NULL prev thread name = '%s'", info->__oldname);
87 #else
88         system_printf ("erroneous thread activation, name is NULL");
89 #endif
90       else
91         {
92           if (exiting)
93             {
94               info->inuse = false;      // FIXME: Do we need this?
95               return 0;
96             }
97
98           info->callfunc (false);
99
100           HANDLE notify = info->notify_detached;
101           /* If func is NULL, the above function has set that to indicate
102              that it doesn't want to alert anyone with a SetEvent and should
103              just be marked as no longer inuse.  Hopefully the function knows
104              what it is doing.  */
105           if (!info->func)
106             info->release (false);
107           else
108             {
109 #ifdef DEBUGGING
110               info->func = NULL;        // catch erroneous activation
111               info->__oldname = info->__name;
112 #endif
113               info->__name = NULL;
114               SetEvent (info->ev);
115             }
116           if (notify)
117             SetEvent (notify);
118         }
119       switch (WaitForSingleObject (info->thread_sync, INFINITE))
120         {
121         case WAIT_OBJECT_0:
122           continue;
123         default:
124           api_fatal ("WFSO failed, %E");
125           break;
126         }
127     }
128 }
129
130 /* Overflow stub called by cygthread constructor. Calls specified function
131    and then exits the thread.  */
132 DWORD WINAPI
133 cygthread::simplestub (VOID *arg)
134 {
135   cygthread *info = (cygthread *) arg;
136   _my_tls._ctinfo = info;
137   info->stack_ptr = &arg;
138   info->callfunc (true);
139   return 0;
140 }
141
142 /* Start things going.  Called from dll_crt0_1. */
143 void
144 cygthread::init ()
145 {
146   main_thread_id = GetCurrentThreadId ();
147 }
148
149 cygthread *
150 cygthread::freerange ()
151 {
152   cygthread *self = (cygthread *) calloc (1, sizeof (*self));
153   self->is_freerange = true;
154   self->inuse = 1;
155   return self;
156 }
157
158 void * cygthread::operator
159 new (size_t)
160 {
161   cygthread *info;
162
163   /* Search the threads array for an empty slot to use */
164   for (info = threads; info < threads + NTHREADS; info++)
165     if (!InterlockedExchange (&info->inuse, 1))
166       {
167         /* available */
168 #ifdef DEBUGGING
169         if (info->__name)
170           api_fatal ("name not NULL? %s, id %p, i %d", info->__name, info->id, info - threads);
171 #endif
172         goto out;
173       }
174
175 #ifdef DEBUGGING
176   if (!getenv ("CYGWIN_FREERANGE_NOCHECK"))
177     api_fatal ("overflowed cygwin thread pool");
178   else
179     thread_printf ("overflowed cygwin thread pool");
180 #endif
181
182   info = freerange ();  /* exhausted thread pool */
183
184 out:
185   return info;
186 }
187
188 cygthread::cygthread (LPTHREAD_START_ROUTINE start, size_t n, void *param,
189                       const char *name, HANDLE notify)
190  : __name (name), func (start), arglen (n), arg (param), notify_detached (notify)
191 {
192   thread_printf ("name %s, id %p", name, id);
193   HANDLE htobe;
194   if (h)
195     {
196       if (ev)
197         ResetEvent (ev);
198       while (!thread_sync)
199         low_priority_sleep (0);
200       SetEvent (thread_sync);
201       thread_printf ("activated name '%s', thread_sync %p for thread %p", name, thread_sync, id);
202       htobe = h;
203     }
204   else
205     {
206       stack_ptr = NULL;
207       htobe = CreateThread (&sec_none_nih, 0, is_freerange ? simplestub : stub,
208                             this, 0, &id);
209       if (!htobe)
210         api_fatal ("CreateThread failed for %s - %p<%p>, %E", name, h, id);
211       thread_printf ("created name '%s', thread %p, id %p", name, h, id);
212 #ifdef DEBUGGING
213       terminated = false;
214 #endif
215     }
216
217   if (n)
218     {
219       while (!ev)
220         low_priority_sleep (0);
221       WaitForSingleObject (ev, INFINITE);
222       ResetEvent (ev);
223     }
224   h = htobe;
225 }
226
227 /* Return the symbolic name of the current thread for debugging.
228  */
229 const char *
230 cygthread::name (DWORD tid)
231 {
232   const char *res = NULL;
233   if (!tid)
234     tid = GetCurrentThreadId ();
235
236   if (tid == main_thread_id)
237     return "main";
238
239   for (DWORD i = 0; i < NTHREADS; i++)
240     if (threads[i].id == tid)
241       {
242         res = threads[i].__name ?: "exiting thread";
243         break;
244       }
245
246   if (!res)
247     {
248       __small_sprintf (_my_tls.locals.unknown_thread_name, "unknown (%p)", tid);
249       res = _my_tls.locals.unknown_thread_name;
250     }
251
252   return res;
253 }
254
255 cygthread::operator
256 HANDLE ()
257 {
258   while (!ev)
259     low_priority_sleep (0);
260   return ev;
261 }
262
263 void
264 cygthread::release (bool nuke_h)
265 {
266   if (nuke_h)
267     h = NULL;
268 #ifdef DEBUGGING
269   __oldname = __name;
270   debug_printf ("released thread '%s'", __oldname);
271 #endif
272   __name = NULL;
273   func = NULL;
274   /* Must be last */
275   if (!InterlockedExchange (&inuse, 0))
276 #ifdef DEBUGGING
277     api_fatal ("released a thread that was not inuse");
278 #else
279     system_printf ("released a thread that was not inuse");
280 #endif
281 }
282
283 /* Forcibly terminate a thread. */
284 bool
285 cygthread::terminate_thread ()
286 {
287   bool terminated = true;
288   debug_printf ("thread '%s', id %p, inuse %d, stack_ptr %p", __name, id, inuse, stack_ptr);
289   while (inuse && !stack_ptr)
290     low_priority_sleep (0);
291
292   if (!inuse)
293     goto force_notterminated;
294
295   TerminateThread (h, 0);
296   WaitForSingleObject (h, INFINITE);
297   CloseHandle (h);
298
299   if (!inuse || exiting)
300     goto force_notterminated;
301
302   if (ev && !(terminated = WaitForSingleObject (ev, 0) != WAIT_OBJECT_0))
303     ResetEvent (ev);
304
305   MEMORY_BASIC_INFORMATION m;
306   memset (&m, 0, sizeof (m));
307   VirtualQuery (stack_ptr, &m, sizeof m);
308
309   if (!m.RegionSize)
310     system_printf ("m.RegionSize 0?  stack_ptr %p", stack_ptr);
311   else if (!VirtualFree (m.AllocationBase, 0, MEM_RELEASE))
312     debug_printf ("VirtualFree of allocation base %p<%p> failed, %E",
313                    stack_ptr, m.AllocationBase);
314
315   if (is_freerange)
316     free (this);
317   else
318     {
319 #ifdef DEBUGGING
320       terminated = true;
321 #endif
322       release (true);
323     }
324
325   goto out;
326
327 force_notterminated:
328   terminated = false;
329 out:
330   return terminated;
331 }
332
333 /* Detach the cygthread from the current thread.  Note that the
334    theory is that cygthreads are only associated with one thread.
335    So, there should be never be multiple threads doing waits
336    on the same cygthread. */
337 bool
338 cygthread::detach (HANDLE sigwait)
339 {
340   bool signalled = false;
341   bool thread_was_reset = false;
342   if (!inuse)
343     system_printf ("called detach but inuse %d, thread %p?", inuse, id);
344   else
345     {
346       DWORD res;
347
348       if (!sigwait)
349         /* If the caller specified a special handle for notification, wait for that.
350            This assumes that the thread in question is auto releasing. */
351         res = WaitForSingleObject (*this, INFINITE);
352       else
353         {
354           /* Lower our priority and give priority to the read thread */
355           HANDLE hth = GetCurrentThread ();
356           LONG prio = GetThreadPriority (hth);
357           ::SetThreadPriority (hth, THREAD_PRIORITY_BELOW_NORMAL);
358
359           HANDLE w4[2];
360           unsigned n = 2;
361           DWORD howlong = INFINITE;
362           w4[0] = sigwait;
363           w4[1] = signal_arrived;
364           /* For a description of the below loop see the end of this file */
365           for (int i = 0; i < 2; i++)
366             switch (res = WaitForMultipleObjects (n, w4, FALSE, howlong))
367               {
368               case WAIT_OBJECT_0:
369                 if (n == 1)
370                   howlong = 50;
371                 break;
372               case WAIT_OBJECT_0 + 1:
373                 n = 1;
374                 if (i--)
375                   howlong = 50;
376                 break;
377               case WAIT_TIMEOUT:
378                 break;
379               default:
380                 if (!exiting)
381                   {
382                     system_printf ("WFMO failed waiting for cygthread '%s', %E", __name);
383                     for (unsigned j = 0; j < n; j++)
384                       switch (WaitForSingleObject (w4[j], 0))
385                         {
386                         case WAIT_OBJECT_0:
387                         case WAIT_TIMEOUT:
388                           break;
389                         default:
390                           system_printf ("%s handle %p is bad", (j ? "signal_arrived" : "semaphore"), w4[j]);
391                           break;
392                         }
393                     api_fatal ("exiting on fatal error");
394                   }
395                 break;
396               }
397           /* WAIT_OBJECT_0 means that the thread successfully read something,
398              so wait for the cygthread to "terminate". */
399           if (res == WAIT_OBJECT_0)
400             WaitForSingleObject (*this, INFINITE);
401           else
402             {
403               /* Thread didn't terminate on its own, so maybe we have to
404                  do it. */
405               signalled = terminate_thread ();
406               /* Possibly the thread completed *just* before it was
407                  terminated.  Detect this. If this happened then the
408                  read was not terminated on a signal. */
409               if (WaitForSingleObject (sigwait, 0) == WAIT_OBJECT_0)
410                 signalled = false;
411               if (signalled)
412                 set_sig_errno (EINTR);
413               thread_was_reset = true;
414             }
415           ::SetThreadPriority (hth, prio);
416         }
417
418       thread_printf ("%s returns %d, id %p", sigwait ? "WFMO" : "WFSO",
419                      res, id);
420
421       if (thread_was_reset)
422         /* already handled */;
423       else if (is_freerange)
424         {
425           CloseHandle (h);
426           free (this);
427         }
428       else
429         {
430           ResetEvent (*this);
431           /* Mark the thread as available by setting inuse to zero */
432           InterlockedExchange (&inuse, 0);
433         }
434     }
435   return signalled;
436 }
437
438 void
439 cygthread::terminate ()
440 {
441   exiting = 1;
442 }
443
444 /* The below is an explanation of synchronization loop in cygthread::detach.
445    The intent is that the loop will always try hard to wait for both
446    synchronization events from the reader thread but will exit with
447    res == WAIT_TIMEOUT if a signal occurred and the reader thread is
448    still blocked.
449
450     case 0 - no signal
451
452     i == 0 (howlong == INFINITE)
453         W0 activated
454         howlong not set because n != 1
455         just loop
456
457     i == 1 (howlong == INFINITE)
458         W0 activated
459         howlong not set because n != 1
460         just loop (to exit loop) - no signal
461
462     i == 2 (howlong == INFINITE)
463         exit loop
464
465     case 1 - signal before thread initialized
466
467     i == 0 (howlong == INFINITE)
468         WO + 1 activated
469         n set to 1
470         howlong untouched because i-- == 0
471         loop
472
473     i == 0 (howlong == INFINITE)
474         W0 must be activated
475         howlong set to 50 because n == 1
476
477     i == 1 (howlong == 50)
478         W0 activated
479         loop (to exit loop) - no signal
480
481         WAIT_TIMEOUT activated
482         signal potentially detected
483         loop (to exit loop)
484
485     i == 2 (howlong == 50)
486         exit loop
487
488     case 2 - signal after thread initialized
489
490     i == 0 (howlong == INFINITE)
491         W0 activated
492         howlong not set because n != 1
493         loop
494
495     i == 1 (howlong == INFINITE)
496         W0 + 1 activated
497         n set to 1
498         howlong set to 50 because i-- != 0
499         loop
500
501     i == 1 (howlong == 50)
502         W0 activated
503         loop (to exit loop) - no signal
504
505         WAIT_TIMEOUT activated
506         loop (to exit loop) - signal
507
508     i == 2 (howlong == 50)
509         exit loop
510 */