3 Copyright 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2008, 2009
6 This software is a copyrighted work licensed under the terms of the
7 Cygwin license. Please consult the file "CYGWIN_LICENSE" for
11 #include "miscfuncs.h"
18 static cygthread NO_COPY threads[32];
19 #define NTHREADS (sizeof (threads) / sizeof (threads[0]))
21 DWORD NO_COPY cygthread::main_thread_id;
22 bool NO_COPY cygthread::exiting;
25 cygthread::callfunc (bool issimplestub)
35 ev = CreateEvent (&sec_none_nih, TRUE, FALSE, NULL);
36 pass_arg = alloca (arglen);
37 memcpy (pass_arg, arg, arglen);
42 /* Wait for main thread to assign 'h' */
44 low_priority_sleep (0);
49 /* Cygwin threads should not call ExitThread directly */
51 /* ...so the above should always return */
54 /* Initial stub called by cygthread constructor. Performs initial
55 per-thread initialization and loops waiting for another thread function
58 cygthread::stub (VOID *arg)
60 cygthread *info = (cygthread *) arg;
61 _my_tls._ctinfo = info;
62 if (info->arg == cygself)
66 CloseHandle (info->ev);
67 CloseHandle (info->thread_sync);
69 info->ev = info->thread_sync = info->stack_ptr = NULL;
73 info->stack_ptr = &arg;
74 debug_printf ("thread '%s', id %p, stack_ptr %p", info->name (), info->id, info->stack_ptr);
77 info->ev = CreateEvent (&sec_none_nih, TRUE, FALSE, NULL);
78 info->thread_sync = CreateEvent (&sec_none_nih, FALSE, FALSE, NULL);
86 system_printf ("erroneous thread activation, name is NULL prev thread name = '%s'", info->__oldname);
88 system_printf ("erroneous thread activation, name is NULL");
94 info->inuse = false; // FIXME: Do we need this?
98 info->callfunc (false);
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
106 info->release (false);
110 info->func = NULL; // catch erroneous activation
111 info->__oldname = info->__name;
119 switch (WaitForSingleObject (info->thread_sync, INFINITE))
124 api_fatal ("WFSO failed, %E");
130 /* Overflow stub called by cygthread constructor. Calls specified function
131 and then exits the thread. */
133 cygthread::simplestub (VOID *arg)
135 cygthread *info = (cygthread *) arg;
136 _my_tls._ctinfo = info;
137 info->stack_ptr = &arg;
138 info->callfunc (true);
142 /* Start things going. Called from dll_crt0_1. */
146 main_thread_id = GetCurrentThreadId ();
150 cygthread::freerange ()
152 cygthread *self = (cygthread *) calloc (1, sizeof (*self));
153 self->is_freerange = true;
158 void * cygthread::operator
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))
170 api_fatal ("name not NULL? %s, id %p, i %d", info->__name, info->id, info - threads);
176 if (!getenv ("CYGWIN_FREERANGE_NOCHECK"))
177 api_fatal ("overflowed cygwin thread pool");
179 thread_printf ("overflowed cygwin thread pool");
182 info = freerange (); /* exhausted thread pool */
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)
192 thread_printf ("name %s, id %p", name, id);
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);
207 htobe = CreateThread (&sec_none_nih, 0, is_freerange ? simplestub : stub,
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);
220 low_priority_sleep (0);
221 WaitForSingleObject (ev, INFINITE);
227 /* Return the symbolic name of the current thread for debugging.
230 cygthread::name (DWORD tid)
232 const char *res = NULL;
234 tid = GetCurrentThreadId ();
236 if (tid == main_thread_id)
239 for (DWORD i = 0; i < NTHREADS; i++)
240 if (threads[i].id == tid)
242 res = threads[i].__name ?: "exiting thread";
248 __small_sprintf (_my_tls.locals.unknown_thread_name, "unknown (%p)", tid);
249 res = _my_tls.locals.unknown_thread_name;
259 low_priority_sleep (0);
264 cygthread::release (bool nuke_h)
270 debug_printf ("released thread '%s'", __oldname);
275 if (!InterlockedExchange (&inuse, 0))
277 api_fatal ("released a thread that was not inuse");
279 system_printf ("released a thread that was not inuse");
283 /* Forcibly terminate a thread. */
285 cygthread::terminate_thread ()
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);
293 goto force_notterminated;
295 TerminateThread (h, 0);
296 WaitForSingleObject (h, INFINITE);
299 if (!inuse || exiting)
300 goto force_notterminated;
302 if (ev && !(terminated = WaitForSingleObject (ev, 0) != WAIT_OBJECT_0))
305 MEMORY_BASIC_INFORMATION m;
306 memset (&m, 0, sizeof (m));
307 VirtualQuery (stack_ptr, &m, sizeof m);
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);
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. */
338 cygthread::detach (HANDLE sigwait)
340 bool signalled = false;
341 bool thread_was_reset = false;
343 system_printf ("called detach but inuse %d, thread %p?", inuse, id);
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);
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);
361 DWORD howlong = INFINITE;
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))
372 case WAIT_OBJECT_0 + 1:
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))
390 system_printf ("%s handle %p is bad", (j ? "signal_arrived" : "semaphore"), w4[j]);
393 api_fatal ("exiting on fatal error");
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);
403 /* Thread didn't terminate on its own, so maybe we have to
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)
412 set_sig_errno (EINTR);
413 thread_was_reset = true;
415 ::SetThreadPriority (hth, prio);
418 thread_printf ("%s returns %d, id %p", sigwait ? "WFMO" : "WFSO",
421 if (thread_was_reset)
422 /* already handled */;
423 else if (is_freerange)
431 /* Mark the thread as available by setting inuse to zero */
432 InterlockedExchange (&inuse, 0);
439 cygthread::terminate ()
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
452 i == 0 (howlong == INFINITE)
454 howlong not set because n != 1
457 i == 1 (howlong == INFINITE)
459 howlong not set because n != 1
460 just loop (to exit loop) - no signal
462 i == 2 (howlong == INFINITE)
465 case 1 - signal before thread initialized
467 i == 0 (howlong == INFINITE)
470 howlong untouched because i-- == 0
473 i == 0 (howlong == INFINITE)
475 howlong set to 50 because n == 1
477 i == 1 (howlong == 50)
479 loop (to exit loop) - no signal
481 WAIT_TIMEOUT activated
482 signal potentially detected
485 i == 2 (howlong == 50)
488 case 2 - signal after thread initialized
490 i == 0 (howlong == INFINITE)
492 howlong not set because n != 1
495 i == 1 (howlong == INFINITE)
498 howlong set to 50 because i-- != 0
501 i == 1 (howlong == 50)
503 loop (to exit loop) - no signal
505 WAIT_TIMEOUT activated
506 loop (to exit loop) - signal
508 i == 2 (howlong == 50)