]> sourceware.org Git - newlib-cygwin.git/blame - winsup/cygwin/cygthread.cc
* DevNotes: Add entry cgf-000013.
[newlib-cygwin.git] / winsup / cygwin / cygthread.cc
CommitLineData
b6bd7037
CF
1/* cygthread.cc
2
ff7fca61 3 Copyright 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2008,
bd139e52 4 2009, 2010, 2011 Red Hat, Inc.
b6bd7037
CF
5
6This software is a copyrighted work licensed under the terms of the
7Cygwin license. Please consult the file "CYGWIN_LICENSE" for
8details. */
9
b6bd7037 10#include "winsup.h"
ade47a34 11#include "miscfuncs.h"
d4d59223 12#include <stdlib.h>
1d380f59 13#include "sigproc.h"
d1eb7a46 14#include "cygtls.h"
bd139e52 15#include "ntdll.h"
b6bd7037
CF
16
17#undef CloseHandle
18
36b63207 19static cygthread NO_COPY threads[64];
b6bd7037
CF
20#define NTHREADS (sizeof (threads) / sizeof (threads[0]))
21
b6bd7037 22DWORD NO_COPY cygthread::main_thread_id;
d525130f 23bool NO_COPY cygthread::exiting;
d4d59223 24
267e201d
CF
25void
26cygthread::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)
8d0f58ef 36 ev = CreateEvent (&sec_none_nih, TRUE, FALSE, NULL);
267e201d
CF
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)
084ea510 45 yield ();
267e201d
CF
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
8d0bc156 55/* Initial stub called by cygthread constructor. Performs initial
ec98d19a 56 per-thread initialization and loops waiting for another thread function
8d0bc156 57 to execute. */
b6bd7037
CF
58DWORD WINAPI
59cygthread::stub (VOID *arg)
d1eb7a46 60{
b6bd7037 61 cygthread *info = (cygthread *) arg;
8cb359d9 62 _my_tls._ctinfo = info;
c4ec64d7 63 if (info->arg == cygself)
e5d6d535
CF
64 {
65 if (info->ev)
66 {
67 CloseHandle (info->ev);
68 CloseHandle (info->thread_sync);
69 }
2d1d1eb1 70 info->ev = info->thread_sync = info->stack_ptr = NULL;
e5d6d535 71 }
c4ec64d7 72 else
3f5046a5 73 {
73afb2ab 74 info->stack_ptr = &arg;
57ba174f 75 debug_printf ("thread '%s', id %p, stack_ptr %p", info->name (), info->id, info->stack_ptr);
e5d6d535
CF
76 if (!info->ev)
77 {
8d0f58ef 78 info->ev = CreateEvent (&sec_none_nih, TRUE, FALSE, NULL);
e5d6d535
CF
79 info->thread_sync = CreateEvent (&sec_none_nih, FALSE, FALSE, NULL);
80 }
3f5046a5 81 }
2d1d1eb1 82
b6bd7037
CF
83 while (1)
84 {
63fcc6d4
CF
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
a7a5d0ba
CF
91 else
92 {
538776b7
CF
93 if (exiting)
94 {
95 info->inuse = false; // FIXME: Do we need this?
96 return 0;
97 }
b6bd7037 98
267e201d 99 info->callfunc (false);
b6bd7037 100
ec98d19a 101 HANDLE notify = info->notify_detached;
74d8e12e 102 /* If func is NULL, the above function has set that to indicate
4ee52924
CF
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
ec98d19a 105 what it is doing. */
4ee52924
CF
106 if (!info->func)
107 info->release (false);
108 else
109 {
1524ae42 110#ifdef DEBUGGING
4ee52924
CF
111 info->func = NULL; // catch erroneous activation
112 info->__oldname = info->__name;
1524ae42 113#endif
4ee52924
CF
114 info->__name = NULL;
115 SetEvent (info->ev);
116 }
ec98d19a
CF
117 if (notify)
118 SetEvent (notify);
a7a5d0ba 119 }
3f5046a5
CF
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 }
b6bd7037
CF
128 }
129}
130
3f5046a5
CF
131/* Overflow stub called by cygthread constructor. Calls specified function
132 and then exits the thread. */
133DWORD WINAPI
134cygthread::simplestub (VOID *arg)
d1eb7a46 135{
3f5046a5 136 cygthread *info = (cygthread *) arg;
8cb359d9 137 _my_tls._ctinfo = info;
73afb2ab 138 info->stack_ptr = &arg;
2691168e 139 HANDLE notify = info->notify_detached;
267e201d 140 info->callfunc (true);
2691168e
CF
141 if (notify)
142 SetEvent (notify);
c350feda 143 return 0;
3f5046a5
CF
144}
145
8d0bc156 146/* Start things going. Called from dll_crt0_1. */
b6bd7037
CF
147void
148cygthread::init ()
149{
b6bd7037
CF
150 main_thread_id = GetCurrentThreadId ();
151}
152
d525130f 153cygthread *
d4d59223
CF
154cygthread::freerange ()
155{
156 cygthread *self = (cygthread *) calloc (1, sizeof (*self));
157 self->is_freerange = true;
ef4d65ba 158 self->inuse = 1;
d4d59223
CF
159 return self;
160}
161
b6bd7037
CF
162void * cygthread::operator
163new (size_t)
164{
8d0bc156 165 cygthread *info;
b6bd7037 166
d525130f
CF
167 /* Search the threads array for an empty slot to use */
168 for (info = threads; info < threads + NTHREADS; info++)
e5d6d535 169 if (!InterlockedExchange (&info->inuse, 1))
d525130f 170 {
9dbe3289 171 /* available */
1524ae42 172#ifdef DEBUGGING
d525130f 173 if (info->__name)
2eeb0e70 174 api_fatal ("name not NULL? %s, id %p, i %d", info->__name, info->id, info - threads);
1524ae42 175#endif
d525130f
CF
176 goto out;
177 }
aea1f301 178
5bf785a0 179#ifdef DEBUGGING
faf42105
CF
180 if (!getenv ("CYGWIN_FREERANGE_NOCHECK"))
181 api_fatal ("overflowed cygwin thread pool");
ef4d65ba 182 else
faf42105 183 thread_printf ("overflowed cygwin thread pool");
5bf785a0 184#endif
d525130f
CF
185
186 info = freerange (); /* exhausted thread pool */
187
188out:
d525130f 189 return info;
b6bd7037
CF
190}
191
53ad6f13
CF
192/* This function is called via QueueUserAPC. Apparently creating threads
193 asynchronously is a huge performance win on Win64. */
194void CALLBACK
195cygthread::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
4db1bd40
CF
203void
204cygthread::create ()
b6bd7037 205{
b9874a0c 206 thread_printf ("name %s, id %p, this %p", __name, id, this);
267e201d 207 HANDLE htobe;
e5d6d535 208 if (h)
5ffec1d1 209 {
267e201d
CF
210 if (ev)
211 ResetEvent (ev);
e5d6d535 212 while (!thread_sync)
084ea510 213 yield ();
e5d6d535 214 SetEvent (thread_sync);
b9874a0c 215 thread_printf ("activated name '%s', thread_sync %p for id %p", __name, thread_sync, id);
267e201d 216 htobe = h;
5ffec1d1 217 }
5ec14fe4 218 else
e5d6d535 219 {
73afb2ab 220 stack_ptr = NULL;
267e201d
CF
221 htobe = CreateThread (&sec_none_nih, 0, is_freerange ? simplestub : stub,
222 this, 0, &id);
223 if (!htobe)
b9874a0c
CF
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);
7a2ba9db 226#ifdef DEBUGGING
63fcc6d4 227 terminated = false;
7a2ba9db 228#endif
e5d6d535 229 }
267e201d 230
4db1bd40 231 if (arglen)
267e201d
CF
232 {
233 while (!ev)
084ea510 234 yield ();
267e201d
CF
235 WaitForSingleObject (ev, INFINITE);
236 ResetEvent (ev);
237 }
238 h = htobe;
b6bd7037
CF
239}
240
241/* Return the symbolic name of the current thread for debugging.
242 */
243const char *
244cygthread::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
e553226c
CF
260 if (res)
261 /* ok */;
262 else if (!_main_tls)
263 res = "main";
264 else
b6bd7037 265 {
24515d65
CF
266 __small_sprintf (_my_tls.locals.unknown_thread_name, "unknown (%p)", tid);
267 res = _my_tls.locals.unknown_thread_name;
b6bd7037 268 }
b6bd7037
CF
269 return res;
270}
271
272cygthread::operator
273HANDLE ()
274{
275 while (!ev)
084ea510 276 yield ();
b6bd7037
CF
277 return ev;
278}
279
9c0d960d 280void
63fcc6d4 281cygthread::release (bool nuke_h)
9c0d960d 282{
63fcc6d4
CF
283 if (nuke_h)
284 h = NULL;
7a2ba9db 285#ifdef DEBUGGING
63fcc6d4 286 __oldname = __name;
538776b7 287 debug_printf ("released thread '%s'", __oldname);
7a2ba9db 288#endif
9c0d960d 289 __name = NULL;
4ee52924 290 func = NULL;
e41ff609 291 /* Must be last */
4ee52924
CF
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
9c0d960d
CF
298}
299
1d380f59 300/* Forcibly terminate a thread. */
85a798d6 301bool
1d380f59
CF
302cygthread::terminate_thread ()
303{
85a798d6 304 bool terminated = true;
c76ca047 305 debug_printf ("thread '%s', id %p, inuse %d, stack_ptr %p", __name, id, inuse, stack_ptr);
57ba174f 306 while (inuse && !stack_ptr)
084ea510 307 yield ();
57ba174f 308
63fcc6d4 309 if (!inuse)
cc9440b6 310 goto force_notterminated;
264f41f0 311
0c55f6ed
CF
312 TerminateThread (h, 0);
313 WaitForSingleObject (h, INFINITE);
e5d6d535
CF
314 CloseHandle (h);
315
cc9440b6
CF
316 if (!inuse || exiting)
317 goto force_notterminated;
318
bd139e52 319 if (ev && !(terminated = !IsEventSignalled (ev)))
8d0f58ef 320 ResetEvent (ev);
9bc36097 321
1d380f59
CF
322 MEMORY_BASIC_INFORMATION m;
323 memset (&m, 0, sizeof (m));
0c55f6ed 324 VirtualQuery (stack_ptr, &m, sizeof m);
1d380f59 325
73afb2ab
CF
326 if (!m.RegionSize)
327 system_printf ("m.RegionSize 0? stack_ptr %p", stack_ptr);
328 else if (!VirtualFree (m.AllocationBase, 0, MEM_RELEASE))
979233a5 329 debug_printf ("VirtualFree of allocation base %p<%p> failed, %E",
73afb2ab 330 stack_ptr, m.AllocationBase);
1d380f59 331
3786526e
CF
332 if (is_freerange)
333 free (this);
334 else
8d0f58ef
CF
335 {
336#ifdef DEBUGGING
337 terminated = true;
338#endif
339 release (true);
340 }
264f41f0 341
cc9440b6
CF
342 goto out;
343
344force_notterminated:
345 terminated = false;
346out:
85a798d6 347 return terminated;
1d380f59
CF
348}
349
8d0bc156 350/* Detach the cygthread from the current thread. Note that the
3f5046a5 351 theory is that cygthreads are only associated with one thread.
9dbe3289
CF
352 So, there should be never be multiple threads doing waits
353 on the same cygthread. */
8bce0d72
CF
354bool
355cygthread::detach (HANDLE sigwait)
b6bd7037 356{
8bce0d72 357 bool signalled = false;
cc9440b6 358 bool thread_was_reset = false;
e5d6d535
CF
359 if (!inuse)
360 system_printf ("called detach but inuse %d, thread %p?", inuse, id);
1524ae42 361 else
b6bd7037 362 {
1d380f59
CF
363 DWORD res;
364
8bce0d72 365 if (!sigwait)
ec98d19a
CF
366 /* If the caller specified a special handle for notification, wait for that.
367 This assumes that the thread in question is auto releasing. */
dc000a83 368 res = WaitForSingleObject (*this, INFINITE);
1d380f59
CF
369 else
370 {
cc9440b6
CF
371 /* Lower our priority and give priority to the read thread */
372 HANDLE hth = GetCurrentThread ();
373 LONG prio = GetThreadPriority (hth);
0c55f6ed 374 ::SetThreadPriority (hth, THREAD_PRIORITY_BELOW_NORMAL);
cc9440b6 375
2addde8c
CF
376 HANDLE w4[2];
377 unsigned n = 2;
cc9440b6 378 DWORD howlong = INFINITE;
2addde8c 379 w4[0] = sigwait;
962f9a2c 380 set_thread_waiting here (w4[1]);
cc9440b6
CF
381 /* For a description of the below loop see the end of this file */
382 for (int i = 0; i < 2; i++)
2addde8c 383 switch (res = WaitForMultipleObjects (n, w4, FALSE, howlong))
cc9440b6
CF
384 {
385 case WAIT_OBJECT_0:
386 if (n == 1)
387 howlong = 50;
388 break;
2addde8c 389 case WAIT_OBJECT_0 + 1:
cc9440b6
CF
390 n = 1;
391 if (i--)
392 howlong = 50;
393 break;
394 case WAIT_TIMEOUT:
395 break;
396 default:
397 if (!exiting)
2addde8c
CF
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 }
cc9440b6
CF
412 break;
413 }
414 /* WAIT_OBJECT_0 means that the thread successfully read something,
415 so wait for the cygthread to "terminate". */
9508ebc5 416 if (res == WAIT_OBJECT_0)
0c55f6ed 417 WaitForSingleObject (*this, INFINITE);
85a798d6 418 else
1d380f59 419 {
cc9440b6
CF
420 /* Thread didn't terminate on its own, so maybe we have to
421 do it. */
85a798d6 422 signalled = terminate_thread ();
cc9440b6
CF
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;
1d380f59 431 }
0c55f6ed 432 ::SetThreadPriority (hth, prio);
1d380f59
CF
433 }
434
8bce0d72 435 thread_printf ("%s returns %d, id %p", sigwait ? "WFMO" : "WFSO",
1d380f59 436 res, id);
5ec14fe4 437
cc9440b6 438 if (thread_was_reset)
1d380f59
CF
439 /* already handled */;
440 else if (is_freerange)
d4d59223
CF
441 {
442 CloseHandle (h);
443 free (this);
444 }
445 else
446 {
5ec14fe4 447 ResetEvent (*this);
e5d6d535 448 /* Mark the thread as available by setting inuse to zero */
0c55f6ed 449 InterlockedExchange (&inuse, 0);
d4d59223 450 }
b6bd7037 451 }
8bce0d72 452 return signalled;
b6bd7037 453}
aea1f301
CF
454
455void
456cygthread::terminate ()
457{
d525130f 458 exiting = 1;
aea1f301 459}
cc9440b6
CF
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*/
This page took 0.343846 seconds and 5 git commands to generate.