OSDN Git Service

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