Cygwin: flock: Fix overlap handling in lf_setlock() and lf_clearlock()
[newlib-cygwin.git] / winsup / cygwin / cygthread.cc
blob4f160975311b699b4df93241856b1cda980a9c16
1 /* cygthread.cc
3 This software is a copyrighted work licensed under the terms of the
4 Cygwin license. Please consult the file "CYGWIN_LICENSE" for
5 details. */
7 #include "winsup.h"
8 #include "miscfuncs.h"
9 #include <stdlib.h>
10 #include "sigproc.h"
11 #include "cygtls.h"
12 #include "ntdll.h"
14 #undef CloseHandle
16 static cygthread NO_COPY threads[64];
17 #define NTHREADS (sizeof (threads) / sizeof (threads[0]))
19 DWORD NO_COPY cygthread::main_thread_id;
20 bool NO_COPY cygthread::exiting;
22 void
23 cygthread::callfunc (bool issimplestub)
25 void *pass_arg;
26 if (arg == cygself)
27 pass_arg = this;
28 else if (!arglen)
29 pass_arg = arg;
30 else
32 if (issimplestub)
33 ev = CreateEvent (&sec_none_nih, TRUE, FALSE, NULL);
34 pass_arg = alloca (arglen);
35 memcpy (pass_arg, arg, arglen);
36 SetEvent (ev);
38 if (issimplestub)
40 /* Wait for main thread to assign 'h' */
41 while (!h)
42 yield ();
43 if (ev)
44 CloseHandle (ev);
45 ev = h;
47 /* Cygwin threads should not call ExitThread directly */
48 func (pass_arg);
49 /* ...so the above should always return */
52 /* Initial stub called by cygthread constructor. Performs initial
53 per-thread initialization and loops waiting for another thread function
54 to execute. */
55 DWORD
56 cygthread::stub (VOID *arg)
58 cygthread *info = (cygthread *) arg;
59 _my_tls._ctinfo = info;
60 if (info->arg == cygself)
62 if (info->ev)
64 CloseHandle (info->ev);
65 CloseHandle (info->thread_sync);
67 info->ev = info->thread_sync = info->stack_ptr = NULL;
69 else
71 info->stack_ptr = &arg;
72 debug_printf ("thread '%s', id %y, stack_ptr %p", info->name (), info->id, info->stack_ptr);
73 if (!info->ev)
75 info->ev = CreateEvent (&sec_none_nih, TRUE, FALSE, NULL);
76 info->thread_sync = CreateEvent (&sec_none_nih, FALSE, FALSE, NULL);
80 while (1)
82 if (!info->__name)
83 #ifdef DEBUGGING
84 system_printf ("erroneous thread activation, name is NULL prev thread name = '%s'", info->__oldname);
85 #else
86 system_printf ("erroneous thread activation, name is NULL");
87 #endif
88 else
90 SetThreadName (info->id, info->__name);
91 info->callfunc (false);
93 HANDLE notify = info->notify_detached;
94 /* If func is NULL, the above function has set that to indicate
95 that it doesn't want to alert anyone with a SetEvent and should
96 just be marked as no longer inuse. Hopefully the function knows
97 what it is doing. */
98 if (!info->func)
99 info->release (false);
100 else
102 #ifdef DEBUGGING
103 info->func = NULL; // catch erroneous activation
104 info->__oldname = info->__name;
105 #endif
106 info->__name = NULL;
107 SetEvent (info->ev);
109 if (notify)
110 SetEvent (notify);
112 switch (WaitForSingleObject (info->thread_sync, INFINITE))
114 case WAIT_OBJECT_0:
115 continue;
116 default:
117 api_fatal ("WFSO failed, %E");
118 break;
123 /* Overflow stub called by cygthread constructor. Calls specified function
124 and then exits the thread. */
125 DWORD
126 cygthread::simplestub (VOID *arg)
128 cygthread *info = (cygthread *) arg;
129 _my_tls._ctinfo = info;
130 info->stack_ptr = &arg;
131 HANDLE notify = info->notify_detached;
132 SetThreadName (info->id, info->__name);
133 info->callfunc (true);
134 if (notify)
135 SetEvent (notify);
136 return 0;
139 /* Start things going. Called from dll_crt0_1. */
140 void
141 cygthread::init ()
143 main_thread_id = GetCurrentThreadId ();
146 cygthread *
147 cygthread::freerange ()
149 cygthread *self = (cygthread *) calloc (1, sizeof (*self));
150 self->is_freerange = true;
151 self->inuse = 1;
152 return self;
155 void * cygthread::operator
156 new (size_t)
158 cygthread *info;
160 /* Search the threads array for an empty slot to use */
161 for (info = threads; info < threads + NTHREADS; info++)
162 if (!InterlockedExchange (&info->inuse, 1))
164 /* available */
165 #ifdef DEBUGGING
166 if (info->__name)
167 api_fatal ("name not NULL? %s, id %y, i %ld", info->__name, info->id, info - threads);
168 #endif
169 goto out;
172 #ifdef DEBUGGING
173 if (!getenv ("CYGWIN_FREERANGE_NOCHECK"))
174 api_fatal ("overflowed cygwin thread pool");
175 else
176 thread_printf ("overflowed cygwin thread pool");
177 #endif
179 info = freerange (); /* exhausted thread pool */
181 out:
182 return info;
185 /* This function is called via QueueUserAPC. Apparently creating threads
186 asynchronously is a huge performance win on Win64. */
187 void CALLBACK
188 cygthread::async_create (ULONG_PTR arg)
190 cygthread *that = (cygthread *) arg;
191 that->create ();
192 ::SetThreadPriority (that->h, THREAD_PRIORITY_HIGHEST);
193 that->zap_h ();
196 void
197 cygthread::create ()
199 thread_printf ("name %s, id %y, this %p", __name, id, this);
200 HANDLE htobe;
201 if (h)
203 if (ev)
204 ResetEvent (ev);
205 while (!thread_sync)
206 yield ();
207 SetEvent (thread_sync);
208 thread_printf ("activated name '%s', thread_sync %p for id %y", __name, thread_sync, id);
209 htobe = h;
211 else
213 stack_ptr = NULL;
214 htobe = CreateThread (&sec_none_nih, 0, is_freerange ? simplestub : stub,
215 this, 0, &id);
216 if (!htobe)
217 api_fatal ("CreateThread failed for %s - %p<%y>, %E", __name, h, id);
218 thread_printf ("created name '%s', thread %p, id %y", __name, h, id);
219 #ifdef DEBUGGING
220 terminated = false;
221 #endif
224 if (arglen)
226 while (!ev)
227 yield ();
228 WaitForSingleObject (ev, INFINITE);
229 ResetEvent (ev);
231 h = htobe;
234 /* Return the symbolic name of the current thread for debugging.
236 const char *
237 cygthread::name (DWORD tid)
239 const char *res = NULL;
240 if (!tid)
241 tid = GetCurrentThreadId ();
243 if (tid == main_thread_id)
244 return "main";
246 for (DWORD i = 0; i < NTHREADS; i++)
247 if (threads[i].id == tid)
249 res = threads[i].__name ?: "exiting thread";
250 break;
253 if (res)
254 /* ok */;
255 else if (!_main_tls)
256 res = "main";
257 else
259 __small_sprintf (_my_tls.locals.unknown_thread_name, "unknown (%y)", tid);
260 res = _my_tls.locals.unknown_thread_name;
262 return res;
265 cygthread::operator
266 HANDLE ()
268 while (!ev)
269 yield ();
270 return ev;
273 void
274 cygthread::release (bool nuke_h)
276 if (nuke_h)
277 h = NULL;
278 #ifdef DEBUGGING
279 __oldname = __name;
280 debug_printf ("released thread '%s'", __oldname);
281 #endif
282 __name = NULL;
283 func = NULL;
284 /* Must be last */
285 if (!InterlockedExchange (&inuse, 0))
286 #ifdef DEBUGGING
287 api_fatal ("released a thread that was not inuse");
288 #else
289 system_printf ("released a thread that was not inuse");
290 #endif
293 /* Forcibly terminate a thread. */
294 bool
295 cygthread::terminate_thread ()
297 bool terminated = true;
298 debug_printf ("thread '%s', id %y, inuse %d, stack_ptr %p", __name, id, inuse, stack_ptr);
299 while (inuse && !stack_ptr)
300 yield ();
302 if (!inuse)
303 goto force_notterminated;
305 if (_my_tls._ctinfo != this)
307 CONTEXT context;
308 context.ContextFlags = CONTEXT_CONTROL;
309 /* SuspendThread makes sure a thread is "booted" from emulation before
310 it is suspended. As such, the emulator hopefully won't be in a bad
311 state (aka, holding any locks) when the thread is terminated. */
312 SuspendThread (h);
313 /* We need to call GetThreadContext, even though we don't care about the
314 context, because SuspendThread is asynchronous and GetThreadContext
315 will make sure the thread is *really* suspended before returning */
316 GetThreadContext (h, &context);
319 TerminateThread (h, 0);
320 WaitForSingleObject (h, INFINITE);
321 CloseHandle (h);
323 if (!inuse || exiting)
324 goto force_notterminated;
326 if (ev && !(terminated = !IsEventSignalled (ev)))
327 ResetEvent (ev);
329 if (is_freerange)
330 free (this);
331 else
333 #ifdef DEBUGGING
334 terminated = true;
335 #endif
336 release (true);
339 goto out;
341 force_notterminated:
342 terminated = false;
343 out:
344 return terminated;
347 /* Detach the cygthread from the current thread. Note that the
348 theory is that cygthreads are only associated with one thread.
349 So, there should be never be multiple threads doing waits
350 on the same cygthread. */
351 bool
352 cygthread::detach (HANDLE sigwait)
354 bool signalled = false;
355 bool thread_was_reset = false;
356 if (!inuse)
357 system_printf ("called detach but inuse %d, thread %y?", inuse, id);
358 else
360 DWORD res;
362 if (!sigwait)
363 /* If the caller specified a special handle for notification, wait for that.
364 This assumes that the thread in question is auto releasing. */
365 res = WaitForSingleObject (*this, INFINITE);
366 else
368 /* Lower our priority and give priority to the read thread */
369 HANDLE hth = GetCurrentThread ();
370 LONG prio = GetThreadPriority (hth);
371 ::SetThreadPriority (hth, THREAD_PRIORITY_BELOW_NORMAL);
373 HANDLE w4[2];
374 unsigned n = 2;
375 DWORD howlong = INFINITE;
376 w4[0] = sigwait;
377 wait_signal_arrived here (w4[1]);
378 /* For a description of the below loop see the end of this file */
379 for (int i = 0; i < 2; i++)
380 switch (res = WaitForMultipleObjects (n, w4, FALSE, howlong))
382 case WAIT_OBJECT_0:
383 if (n == 1)
384 howlong = 50;
385 break;
386 case WAIT_OBJECT_0 + 1:
387 n = 1;
388 if (i--)
389 howlong = 50;
390 break;
391 case WAIT_TIMEOUT:
392 break;
393 default:
394 if (!exiting)
396 system_printf ("WFMO failed waiting for cygthread '%s', %E", __name);
397 for (unsigned j = 0; j < n; j++)
398 switch (WaitForSingleObject (w4[j], 0))
400 case WAIT_OBJECT_0:
401 case WAIT_TIMEOUT:
402 break;
403 default:
404 system_printf ("%s handle %p is bad", (j ? "signal_arrived" : "semaphore"), w4[j]);
405 break;
407 api_fatal ("exiting on fatal error");
409 break;
411 /* WAIT_OBJECT_0 means that the thread successfully read something,
412 so wait for the cygthread to "terminate". */
413 if (res == WAIT_OBJECT_0)
414 WaitForSingleObject (*this, INFINITE);
415 else
417 /* Thread didn't terminate on its own, so maybe we have to
418 do it. */
419 signalled = terminate_thread ();
420 /* Possibly the thread completed *just* before it was
421 terminated. Detect this. If this happened then the
422 read was not terminated on a signal. */
423 if (WaitForSingleObject (sigwait, 0) == WAIT_OBJECT_0)
424 signalled = false;
425 if (signalled)
426 set_sig_errno (EINTR);
427 thread_was_reset = true;
429 ::SetThreadPriority (hth, prio);
432 thread_printf ("%s returns %d, id %y", sigwait ? "WFMO" : "WFSO",
433 res, id);
435 if (thread_was_reset)
436 /* already handled */;
437 else if (is_freerange)
439 CloseHandle (h);
440 free (this);
442 else
444 ResetEvent (*this);
445 /* Mark the thread as available by setting inuse to zero */
446 InterlockedExchange (&inuse, 0);
449 return signalled;
452 void
453 cygthread::terminate ()
455 exiting = 1;
458 /* The below is an explanation of synchronization loop in cygthread::detach.
459 The intent is that the loop will always try hard to wait for both
460 synchronization events from the reader thread but will exit with
461 res == WAIT_TIMEOUT if a signal occurred and the reader thread is
462 still blocked.
464 case 0 - no signal
466 i == 0 (howlong == INFINITE)
467 W0 activated
468 howlong not set because n != 1
469 just loop
471 i == 1 (howlong == INFINITE)
472 W0 activated
473 howlong not set because n != 1
474 just loop (to exit loop) - no signal
476 i == 2 (howlong == INFINITE)
477 exit loop
479 case 1 - signal before thread initialized
481 i == 0 (howlong == INFINITE)
482 WO + 1 activated
483 n set to 1
484 howlong untouched because i-- == 0
485 loop
487 i == 0 (howlong == INFINITE)
488 W0 must be activated
489 howlong set to 50 because n == 1
491 i == 1 (howlong == 50)
492 W0 activated
493 loop (to exit loop) - no signal
495 WAIT_TIMEOUT activated
496 signal potentially detected
497 loop (to exit loop)
499 i == 2 (howlong == 50)
500 exit loop
502 case 2 - signal after thread initialized
504 i == 0 (howlong == INFINITE)
505 W0 activated
506 howlong not set because n != 1
507 loop
509 i == 1 (howlong == INFINITE)
510 W0 + 1 activated
511 n set to 1
512 howlong set to 50 because i-- != 0
513 loop
515 i == 1 (howlong == 50)
516 W0 activated
517 loop (to exit loop) - no signal
519 WAIT_TIMEOUT activated
520 loop (to exit loop) - signal
522 i == 2 (howlong == 50)
523 exit loop