4 * Routines for pre-emptive threading system
6 * Portable Windows Library
8 * Copyright (c) 1993-1998 Equivalence Pty. Ltd.
10 * The contents of this file are subject to the Mozilla Public License
11 * Version 1.0 (the "License"); you may not use this file except in
12 * compliance with the License. You may obtain a copy of the License at
13 * http://www.mozilla.org/MPL/
15 * Software distributed under the License is distributed on an "AS IS"
16 * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
17 * the License for the specific language governing rights and limitations
20 * The Original Code is Portable Windows Library.
22 * The Initial Developer of the Original Code is Equivalence Pty. Ltd.
24 * Portions are Copyright (C) 1993 Free Software Foundation, Inc.
25 * All Rights Reserved.
27 * Contributor(s): ______________________________________.
30 * Revision 1.174 2007/09/05 12:40:11 csoutheren
31 * Add generic test for mutex type
33 * Revision 1.173 2007/09/05 11:58:47 csoutheren
34 * Fixed build on MacOSX
36 * Revision 1.170 2007/08/17 07:29:21 csoutheren
39 * Revision 1.169 2007/08/17 07:05:13 csoutheren
40 * Fix problem with false asserts based on mutex locking
42 * Revision 1.168 2007/08/17 05:29:19 csoutheren
43 * Add field to Linux showing locking thread to assist in debugging
45 * Revision 1.167 2007/07/19 08:11:47 csoutheren
46 * Fix problem with hex in log stream
48 * Revision 1.166 2007/07/06 02:12:14 csoutheren
49 * Add extra memory leak debugging on Linux
50 * Remove compile warnings
52 * Revision 1.165 2007/05/01 10:20:44 csoutheren
53 * Applied 1703617 - Prevention of application deadlock caused by too many timers
54 * Thanks to Fabrizio Ammollo
56 * Revision 1.164 2006/10/23 01:15:16 csoutheren
57 * Revert to revision 1.153 to fix crash problem with SIP connections
59 * Revision 1.153 2006/06/25 21:46:38 dereksmithies
60 * Thanks to Paul Nader for this fix which fixes thread cleanup
61 * issues on SMP machines. Good find.
63 * Revision 1.152 2006/03/01 08:29:33 csoutheren
64 * Applied patch #1439578 PTrace / PThread::PX_ThreadEnd deadlock fix
65 * Thanks to Hannes Friederich
67 * Revision 1.151 2006/01/29 22:35:47 csoutheren
68 * Added fix for thread termination problems on SMP machines
69 * Thanks to Derek Smithies
71 * Revision 1.150 2005/12/05 22:35:24 csoutheren
72 * Only assert in PTimedMutex destructor if _DEBUG is enabled
74 * Revision 1.149 2005/12/04 22:07:26 csoutheren
75 * Fixed uninitialised variable
77 * Revision 1.148 2005/12/01 00:55:19 csoutheren
78 * Removed chance of endless loop in PTimedMutex destructor
80 * Revision 1.147 2005/11/25 00:06:12 csoutheren
81 * Applied patch #1364593 from Hannes Friederich
82 * Also changed so PTimesMutex is no longer descended from PSemaphore on
83 * non-Windows platforms
85 * Revision 1.146 2005/11/22 22:38:36 dsandras
86 * Removed Assert that was causing problem if the mutex is locked when being
89 * Revision 1.145 2005/11/18 22:26:07 dsandras
90 * Removed a few more CONST's to match with previous commit and fix permanent
93 * Revision 1.144 2005/11/14 22:41:53 csoutheren
94 * Reverted Wait and Signal to non-const - there is no way we can guarantee that all
95 * descendant classes everywhere will be changed over, so we have to keep the
98 * Revision 1.143 2005/11/04 09:44:30 csoutheren
99 * Applied patch #1324589
100 * Removed race conditions in PSemaphore and thread handling
101 * Thanks to Frederic Heem
103 * Revision 1.142 2005/11/04 06:56:10 csoutheren
104 * Added new class PSync as abstract base class for all mutex/sempahore classes
105 * Changed PCriticalSection to use Wait/Signal rather than Enter/Leave
106 * Changed Wait/Signal to be const member functions
107 * Renamed PMutex to PTimedMutex and made PMutex synonym for PCriticalSection.
108 * This allows use of very efficient mutex primitives in 99% of cases where timed waits
111 * Revision 1.141 2005/07/22 04:19:18 csoutheren
112 * Removed redundant check of thread ID introduced in last patch
113 * Removed race condition in thread shutdown found by Derek Smithies
115 * Revision 1.140 2005/07/21 13:04:11 csoutheren
116 * Removed race condition where activeThreads list does not contain
117 * thread until some time after thread is started. Fixed by moving
118 * list insertion to immediately after pthread_create, and using lock
120 * Revision 1.139 2005/07/21 00:09:08 csoutheren
121 * Added workaround for braindead behaviour of pthread_kill
122 * Thanks to "martin martin" <acevedoma@hotmail.com>
124 * Revision 1.138 2005/05/03 11:58:46 csoutheren
125 * Fixed various problems reported by valgrind
126 * Thanks to Paul Cadach
128 * Revision 1.137 2005/01/21 21:25:19 csoutheren
129 * Removed incorrect return in PThread::WaitForTermination
131 * Revision 1.136 2005/01/16 23:00:37 csoutheren
132 * Fixed problem when calling WaitForTermination from within the same thread
134 * Revision 1.135 2004/12/21 06:30:55 csoutheren
135 * Added explicit stack size for pthreads to minimise VM usage, thanks to Diana Cionoiu
137 * Revision 1.134 2004/09/02 07:55:44 csoutheren
138 * Added extra PXAbortBlock to WaitForTermination to assist in terminaing
139 * threads under certain conditions
141 * Revision 1.133 2004/06/24 11:29:44 csoutheren
142 * Changed to use pthread_mutex_timedlock for more efficient mutex wait operations
143 * Thanks to Michal Zygmuntowicz
145 * Revision 1.132 2004/06/01 07:42:20 csoutheren
146 * Restored memory allocation checking
147 * Added configure flag to enable, thanks to Derek Smithies
149 * Revision 1.131 2004/05/21 00:49:16 csoutheren
150 * Added PreShutdown to ~PProcess
152 * Revision 1.130 2004/04/27 04:36:47 rjongbloed
153 * Fixed occassional crash on exit due to level 5 trace in PProcess
154 * destructor that needs an undestructed PProcess.
155 * Added some more logging for unblocking threads.
157 * Revision 1.129 2004/04/12 03:35:27 csoutheren
158 * Fixed problems with non-recursuve mutexes and critical sections on
159 * older compilers and libc
161 * Revision 1.128 2004/04/12 00:58:45 csoutheren
162 * Fixed PAtomicInteger on Linux, and modified PMutex to use it
164 * Revision 1.127 2004/04/11 07:58:08 csoutheren
165 * Added configure.in check for recursive mutexes, and changed implementation
166 * without recursive mutexes to use PCriticalSection or atomic word structs
168 * Revision 1.126 2004/03/24 02:37:04 csoutheren
169 * Fixed problem with incorrect usage of sem_timedwait
171 * Revision 1.125 2004/03/23 04:56:23 csoutheren
172 * Added patches to use XPG6 threading under Linux if available
173 * Thanks to Matthew Hodgson
175 * Revision 1.124 2004/02/01 11:23:16 dsandras
176 * Reverted previous Change and removed Yield call from Current (). Fix from Christian Meder <chris@onestepahead.de>. Thanks for your help, Christian!
178 * Revision 1.123 2004/01/31 13:49:18 dominance
179 * Added 2.6 performance fix as proposed by Christian Meder <chris@onestepahead.de>.
181 * Revision 1.122 2003/09/17 09:02:15 csoutheren
182 * Removed memory leak detection code
184 * Revision 1.121 2003/05/16 17:40:55 shawn
185 * On Mac OS X, thread with the highest priority should use fixed priority
186 * scheduling policy. This avoids starvation caused by desktop activity.
188 * Revision 1.120 2003/05/02 00:58:40 dereks
189 * Add test for linux at the end of PMutex::Signal. Thanks Robert!
191 * Revision 1.119 2003/05/02 00:39:11 dereks
192 * Changes to make threading work on Redhat 9
194 * Revision 1.118 2003/04/24 12:03:13 rogerh
195 * Calling pthread_mutex_unlock() on a mutex which is not locked can be
196 * considered an error. NetBSD now enforce this error so we need to quickly
197 * try locking the mutex before unlocking it in ~PThread and ~PSemaphore.
199 * Revision 1.117 2003/04/08 03:29:31 robertj
200 * Fixed IsSuspeneded() so returns TRUE if thread not started yet, this makes
201 * it the same as the Win32 semantics.
203 * Revision 1.116 2003/03/10 15:37:00 rogerh
204 * fix IsTerminated() function.
206 * Revision 1.115 2003/03/07 00:07:15 robertj
207 * Fixed Mac OS X patch which broke every other platform.
209 * Revision 1.114 2003/03/06 08:58:48 rogerh
210 * P_MACOSX now carries the OSRELEASE. Use this to enable better threads
211 * support on Darwin 6.4. Submitted by Shawn.
213 * Revision 1.113 2003/02/20 23:32:00 robertj
214 * More RTEMS support patches, thanks Sebastian Meyer.
216 * Revision 1.112 2003/01/24 10:21:06 robertj
217 * Fixed issues in RTEMS support, thanks Vladimir Nesic
219 * Revision 1.111 2003/01/20 10:13:18 rogerh
220 * NetBSD thread changes
222 * Revision 1.110 2003/01/20 10:05:46 rogerh
223 * NetBSD thread changes
225 * Revision 1.109 2003/01/08 08:47:51 rogerh
226 * Add new Sleep() function for GNU PTH threads.
227 * Taken from NetBSD's package which uses PTH.
228 * Note: I am not sure this works correctly.
230 * Revision 1.108 2003/01/06 18:49:15 rogerh
231 * Back out pthead_kill to pthread_cancel change on NetBSD
233 * Revision 1.107 2002/12/11 05:39:26 robertj
234 * Added logging for file handle changes.
235 * Fixd bug where internal maxHandles not set when increased.
237 * Revision 1.106 2002/12/02 03:57:18 robertj
238 * More RTEMS support patches, thank you Vladimir Nesic.
240 * Revision 1.105 2002/11/22 10:14:07 robertj
241 * QNX port, thanks Xiaodan Tang
243 * Revision 1.104 2002/11/04 16:01:27 rogerh
244 * Using pthread_cancel and not pthread_kill with SIGKILL to terminate a thread
245 * On FreeBSD the thread does not have a handler for SIGKILL, it passes it up
246 * to the main process which gets killed! Assume the other BSDs are the same.
248 * Revision 1.103 2002/10/24 00:40:56 robertj
249 * Put back ability to terminate a thread from that threads context (removed
250 * in revision 1.101) but requires that destructor not do so.
251 * Changed pipe close to allow for possible EINTR, and retry close.
253 * Revision 1.102 2002/10/24 00:25:13 robertj
254 * Changed high load thread problem fix from the termination function to start
255 * function to finally, once and for all (I hope!) fix the race condition.
257 * Revision 1.101 2002/10/23 14:56:22 craigs
258 * Fixed problem with pipe leak under some circumstances
260 * Revision 1.100 2002/10/23 04:29:32 robertj
261 * Improved debugging for thread create/start/stop/destroy.
262 * Fixed race condition bug if auto-delete thread starts and completes before
263 * pthread_create returns, PX_threadId is not set yet!
265 * Revision 1.99 2002/10/22 07:42:52 robertj
266 * Added extra debugging for file handle and thread leak detection.
268 * Revision 1.98 2002/10/18 03:05:39 robertj
269 * Fixed thread leak caused by fixing the thread crash a few revisions back,
270 * caused by strange pthreads behaviour, at least under Linux.
272 * Revision 1.97 2002/10/17 13:44:27 robertj
273 * Port to RTEMS, thanks Vladimir Nesic.
275 * Revision 1.96 2002/10/17 12:57:24 robertj
276 * Added ability to increase maximum file handles on a process.
278 * Revision 1.95 2002/10/16 11:26:29 rogerh
279 * Add missing include. Noticed by Matthias on the GnomeMeeting IRC
281 * Revision 1.94 2002/10/10 03:09:48 robertj
282 * Fixed high load race condition when starting threads.
284 * Revision 1.93 2002/10/05 05:22:43 robertj
285 * Fixed adding GetThreadId() function.
287 * Revision 1.92 2002/10/01 06:27:48 robertj
288 * Added bullet proofing against possible EINTR error returns on all pthread
289 * functions when under heavy load. Linux really should NOT do this, but ...
291 * Revision 1.91 2002/09/04 03:14:18 robertj
292 * Backed out changes submitted by Martin Froehlich as they do not appear to
293 * actually do anything other than add a sychronisation point. The variables
294 * the patches intended to protect were already protected.
295 * Fixed bug where if a PMutex was signalled by a thread that did not have it
296 * locked, it would assert but continue to alter PMutex variables such that
297 * a deadlock or crash is likely.
299 * Revision 1.90 2002/08/29 01:50:40 robertj
300 * Changed the pthread_create so does retries if get EINTR or EAGAIN errors
301 * which indicate a (possibly) temporary resource limit.
302 * Enabled and adjusted tracing.
304 * Revision 1.89 2002/08/22 13:05:57 craigs
305 * Fixed problems with mutex implementation thanks to Martin Froehlich
307 * Revision 1.88 2002/07/15 06:56:59 craigs
308 * Fixed missing brace
310 * Revision 1.87 2002/07/15 06:39:23 craigs
311 * Added function to allow raising of per-process file handle limit
313 * Revision 1.86 2002/06/27 06:38:58 robertj
314 * Changes to remove memory leak display for things that aren't memory leaks.
316 * Revision 1.85 2002/06/27 02:04:01 robertj
317 * Fixed NetBSD compatibility issue, thanks Motoyuki OHMORI.
319 * Revision 1.84 2002/06/04 00:25:31 robertj
320 * Fixed incorrectly initialised trace indent, thanks Artis Kugevics
322 * Revision 1.83 2002/05/21 09:13:00 robertj
323 * Fixed problem when using posix recursive mutexes, thanks Artis Kugevics
325 * Revision 1.82 2002/04/24 01:11:37 robertj
326 * Fixed problem with PTRACE_BLOCK indent level being correct across threads.
328 * Revision 1.81 2002/04/16 10:57:26 rogerh
329 * Change WaitForTermination() so it does not use 100% CPU.
330 * Reported by Andrea <ghittino@tiscali.it>
332 * Revision 1.80 2002/01/23 04:26:36 craigs
333 * Added copy constructors for PSemaphore, PMutex and PSyncPoint to allow
334 * use of default copy constructors for objects containing instances of
337 * Revision 1.79 2002/01/10 06:36:58 robertj
338 * Fixed possible resource leak under Solaris, thanks Joegen Baclor
340 * Revision 1.78 2001/12/17 11:06:46 robertj
341 * Removed assert on NULL PThread::Current(), can occur if thread from other
344 * Revision 1.77 2001/10/03 05:11:50 robertj
345 * Fixed PSyncPoint wait with timeout when have pending signals.
347 * Revision 1.76 2001/09/27 23:50:03 craigs
348 * Fixed typo in PSemaphone destructor
350 * Revision 1.75 2001/09/24 10:09:48 rogerh
351 * Fix an uninitialised variable problem.
353 * Revision 1.74 2001/09/20 05:38:25 robertj
354 * Changed PSyncPoint to use pthread cond so timed wait blocks properly.
355 * Also prevented semaphore from being created if subclass does not use it.
357 * Revision 1.73 2001/09/19 17:37:47 craigs
358 * Added support for nested mutexes under Linux
360 * Revision 1.72 2001/09/18 06:53:35 robertj
361 * Made sure suspend can't exit early if get spurious signal
363 * Revision 1.71 2001/09/18 05:56:03 robertj
364 * Fixed numerous problems with thread suspend/resume and signals handling.
366 * Revision 1.70 2001/09/10 03:03:02 robertj
367 * Major change to fix problem with error codes being corrupted in a
368 * PChannel when have simultaneous reads and writes in threads.
369 * Changed threading so does not actually start thread until Resume(), makes
370 * the logic of start up much simpler and more portable.
371 * Quite a bit of tidyin up of the pthreads code.
373 * Revision 1.69 2001/08/30 08:57:40 robertj
374 * Changed calls to usleep to be PThread::Yield(), normalising single
375 * timeslice process swap out.
377 * Revision 1.68 2001/08/20 06:55:45 robertj
378 * Fixed ability to have PMutex::Wait() with times less than one second.
379 * Fixed small error in return value of block on I/O function, not critical.
381 * Revision 1.67 2001/08/07 02:50:03 craigs
382 * Fixed potential race condition in IO blocking
384 * Revision 1.66 2001/07/09 13:23:37 rogerh
385 * Fix a subtle bug in semaphore wait which showed up on FreeBSD
387 * Revision 1.65 2001/05/29 00:49:18 robertj
388 * Added ability to put in a printf %x in thread name to get thread object
389 * address into user settable thread name.
391 * Revision 1.64 2001/05/23 00:18:55 robertj
392 * Added support for real time threads, thanks Erland Lewin.
394 * Revision 1.63 2001/04/20 09:27:25 robertj
395 * Fixed previous change for auto delete threads, must have thread ID zeroed.
397 * Revision 1.62 2001/04/20 09:09:05 craigs
398 * Removed possible race condition whilst shutting down threads
400 * Revision 1.61 2001/03/20 06:44:25 robertj
401 * Lots of changes to fix the problems with terminating threads that are I/O
402 * blocked, especially when doing orderly shutdown of service via SIGTERM.
404 * Revision 1.60 2001/03/14 01:16:11 robertj
405 * Fixed signals processing, now uses housekeeping thread to handle signals
406 * synchronously. This also fixes issues with stopping PServiceProcess.
408 * Revision 1.59 2001/02/25 19:39:42 rogerh
409 * Use a Semaphore on Mac OS X to support threads which are started as 'suspended'
411 * Revision 1.58 2001/02/24 14:49:22 rogerh
412 * Add missing bracket
414 * Revision 1.57 2001/02/24 13:29:34 rogerh
415 * Mac OS X change to avoid Assertion
417 * Revision 1.56 2001/02/24 13:24:24 rogerh
418 * Add PThread support for Mac OS X and Darwin. There is one major issue. This
419 * OS does not suport pthread_kill() and sigwait() so we cannot support the
420 * Suspend() and Resume() functions to start and stop threads and we cannot
421 * create new threads in 'suspended' mode.
422 * Calling Suspend() raises an assertion. Calling Resume() does nothing.
423 * Threads started in 'suspended' mode start immediatly.
425 * Revision 1.55 2001/02/21 22:48:42 robertj
426 * Fixed incorrect test in PSemaphore::WillBlock() just added, thank Artis Kugevics.
428 * Revision 1.54 2001/02/20 00:21:14 robertj
429 * Fixed major bug in PSemapahore::WillBlock(), thanks Tomas Heran.
431 * Revision 1.53 2000/12/21 12:36:32 craigs
432 * Removed potential to stop threads twice
434 * Revision 1.52 2000/12/05 08:24:50 craigs
435 * Fixed problem with EINTR causing havoc
437 * Revision 1.51 2000/11/16 11:06:38 rogerh
438 * Add a better fix for the "user signal 2" aborts seen on FreeBSD 4.2 and above.
439 * We need to sched_yeild() after the pthread_create() to make sure the new thread
440 * actually has a chance to execute. The abort problem was caused when the
441 * resume signal was issued before the thread was ready for it.
443 * Revision 1.50 2000/11/12 23:30:02 craigs
444 * Added extra WaitForTermination to assist bug location
446 * Revision 1.49 2000/11/12 08:16:07 rogerh
447 * This change and the previous change, make pthreads work on FreeBSD 4.2.
448 * FreeBSD has improved its thread signal handling and now correctly generates a
449 * SIGUSR2 signal on a thread (the Resume Signal). However there was no handler
450 * for this signal and applications would abort with "User signal 2".
451 * So, a dummy sigResumeHandler has been added.
453 * Revision 1.48 2000/11/12 07:57:45 rogerh
454 * *** empty log message ***
456 * Revision 1.47 2000/10/31 08:09:51 rogerh
457 * Change return type of PX_GetThreadId() to save unnecessary typecasting
459 * Revision 1.46 2000/10/31 07:52:06 rogerh
460 * Add type casts to allow the code to compile on FreeBSD 4.1.1
462 * Revision 1.45 2000/10/30 05:48:33 robertj
463 * Added assert when get nested mutex.
465 * Revision 1.44 2000/10/24 03:32:40 robertj
466 * Fixed problem where thread that uses PThread::Current() in dtor crashes.
468 * Revision 1.43 2000/10/20 06:11:48 robertj
469 * Added function to change auto delete flag on a thread.
471 * Revision 1.42 2000/09/20 04:24:09 craigs
472 * Added extra tracing, and removed segv on exit when using tracing
474 * Revision 1.41 2000/06/21 01:01:22 robertj
475 * AIX port, thanks Wolfgang Platzer (wolfgang.platzer@infonova.at).
477 * Revision 1.40 2000/04/13 07:21:10 rogerh
478 * Fix typo in #defined
480 * Revision 1.39 2000/04/11 11:38:49 rogerh
481 * More NetBSD Pthread changes
483 * Revision 1.38 2000/04/10 11:47:02 rogerh
484 * Add initial NetBSD pthreads support
486 * Revision 1.37 2000/04/06 12:19:49 rogerh
487 * Add Mac OS X support submitted by Kevin Packard
489 * Revision 1.36 2000/03/20 22:56:34 craigs
490 * Fixed problems with race conditions caused by testing or changing
491 * attributes on a terminated thread. Only occured on a fast machine!
493 * Revision 1.35 2000/03/17 03:45:40 craigs
494 * Fixed problem with connect call hanging
496 * Revision 1.34 2000/03/08 12:17:09 rogerh
497 * Add OpenBSD support
499 * Revision 1.33 2000/02/29 13:18:21 robertj
500 * Added named threads to tracing, thanks to Dave Harvey
502 * Revision 1.32 2000/01/20 08:20:57 robertj
503 * FreeBSD v3 compatibility changes, thanks Roger Hardiman & Motonori Shindo
505 * Revision 1.31 1999/11/18 14:02:57 craigs
506 * Fixed problem with houskeeping thread termination
508 * Revision 1.30 1999/11/15 01:12:56 craigs
509 * Fixed problem with PSemaphore::Wait consuming 100% CPU
511 * Revision 1.29 1999/10/30 13:44:11 craigs
512 * Added correct method of aborting socket operations asynchronously
514 * Revision 1.28 1999/10/24 13:03:30 craigs
515 * Changed to capture io break signal
517 * Revision 1.27 1999/09/23 06:52:16 robertj
518 * Changed PSemaphore to use Posix semaphores.
520 * Revision 1.26 1999/09/03 02:26:25 robertj
521 * Changes to aid in breaking I/O locks on thread termination. Still needs more work esp in BSD!
523 * Revision 1.25 1999/09/02 11:56:35 robertj
524 * Fixed problem with destroying PMutex that is already locked.
526 * Revision 1.24 1999/08/24 13:40:56 craigs
527 * Fixed problem with condwait destorys failing on linux
529 * Revision 1.23 1999/08/23 05:33:45 robertj
530 * Made last threading changes Linux only.
532 * Revision 1.22 1999/08/23 05:14:13 robertj
533 * Removed blocking of interrupt signals as does not work in Linux threads.
535 * Revision 1.21 1999/07/30 00:40:32 robertj
536 * Fixed problem with signal variable in non-Linux platforms
538 * Revision 1.20 1999/07/19 01:32:24 craigs
539 * Changed signals used in pthreads code, is used by linux version.
541 * Revision 1.19 1999/07/15 13:10:55 craigs
542 * Fixed problem with EINTR in nontimed sempahore waits
544 * Revision 1.18 1999/07/15 13:05:33 robertj
545 * Fixed problem with getting EINTR in semaphore wait, is normal, not error.
547 * Revision 1.17 1999/07/11 13:42:13 craigs
548 * pthreads support for Linux
550 * Revision 1.16 1999/05/12 03:29:20 robertj
551 * Fixed problem with semaphore free, done at wrong time.
553 * Revision 1.15 1999/04/29 08:41:26 robertj
554 * Fixed problems with uninitialised mutexes in PProcess.
556 * Revision 1.14 1999/03/16 10:54:16 robertj
557 * Added parameterless version of WaitForTermination.
559 * Revision 1.13 1999/03/16 10:30:37 robertj
560 * Added missing PThread::WaitForTermination function.
562 * Revision 1.12 1999/01/12 12:09:51 robertj
563 * Removed redundent member variable, was in common.
564 * Fixed BSD threads compatibility.
566 * Revision 1.11 1999/01/11 12:05:56 robertj
567 * Fixed some more race conditions in threads.
569 * Revision 1.10 1999/01/11 03:42:26 robertj
570 * Fixed problem with destroying thread automatically.
572 * Revision 1.9 1999/01/09 03:37:28 robertj
573 * Fixed problem with closing thread waiting on semaphore.
574 * Improved efficiency of mutex to use pthread functions directly.
576 * Revision 1.8 1999/01/08 01:31:03 robertj
577 * Support for pthreads under FreeBSD
579 * Revision 1.7 1998/12/15 12:41:07 robertj
580 * Fixed signal handling so can now ^C a pthread version.
582 * Revision 1.6 1998/11/05 09:45:04 robertj
583 * Removed StartImmediate option in thread construction.
585 * Revision 1.5 1998/09/24 04:12:25 robertj
586 * Added open software license.
590 #include <ptlib/socket.h>
591 #include <sched.h> // for sched_yield
593 #include <sys/resource.h>
596 #define SUSPEND_SIG SIGALRM
599 #define SUSPEND_SIG SIGVTALRM
603 #include <mach/mach.h>
604 #include <mach/thread_policy.h>
605 #include <sys/param.h>
606 #include <sys/sysctl.h>
607 // going to need the main thread for adjusting relative priority
608 static pthread_t baseThread
;
611 #ifdef P_HAS_SEMAPHORES_XPG6
612 #include "semaphore.h"
615 int PX_NewHandle(const char *, int);
617 #define PPThreadKill(id, sig) PProcess::Current().PThreadKill(id, sig)
620 #define PAssertPTHREAD(func, args) \
622 unsigned threadOpRetry = 0; \
623 while (PAssertThreadOp(func args, threadOpRetry, #func, __FILE__, __LINE__)); \
626 static BOOL
PAssertThreadOp(int retval
,
628 const char * funcname
,
633 PTRACE_IF(2, retry
> 0, "PWLib\t" << funcname
<< " required " << retry
<< " retries!");
637 if (errno
== EINTR
|| errno
== EAGAIN
) {
638 if (++retry
< 1000) {
642 usleep(10000); // Basically just swap out thread to try and clear blockage
644 return TRUE
; // Return value to try again
646 // Give up and assert
649 PAssertFunc(file
, line
, NULL
, psprintf("Function %s failed", funcname
));
654 PDECLARE_CLASS(PHouseKeepingThread
, PThread
)
656 PHouseKeepingThread()
657 : PThread(1000, NoAutoDeleteThread
, NormalPriority
, "Housekeeper")
658 { closing
= FALSE
; Resume(); }
661 void SetClosing() { closing
= TRUE
; }
668 static pthread_mutex_t MutexInitialiser
= PTHREAD_MUTEX_INITIALIZER
;
674 void PHouseKeepingThread::Main()
676 PProcess
& process
= PProcess::Current();
679 PTimeInterval delay
= process
.timers
.Process();
681 process
.breakBlock
.Wait(delay
);
683 process
.PXCheckSignals();
688 void PProcess::SignalTimerChange()
690 if (housekeepingThread
== NULL
) {
692 BOOL oldIgnoreAllocations
= PMemoryHeap::SetIgnoreAllocations(TRUE
);
694 housekeepingThread
= new PHouseKeepingThread
;
696 PMemoryHeap::SetIgnoreAllocations(oldIgnoreAllocations
);
704 void PProcess::Construct()
707 // get the file descriptor limit
709 PAssertOS(getrlimit(RLIMIT_NOFILE
, &rl
) == 0);
710 maxHandles
= rl
.rlim_cur
;
711 PTRACE(4, "PWLib\tMaximum per-process file handles is " << maxHandles
);
713 maxHandles
= 500; // arbitrary value
716 // initialise the housekeeping thread
717 housekeepingThread
= NULL
;
720 // records the main thread for priority adjusting
721 baseThread
= pthread_self();
728 BOOL
PProcess::SetMaxHandles(int newMax
)
731 // get the current process limit
733 PAssertOS(getrlimit(RLIMIT_NOFILE
, &rl
) == 0);
735 // set the new current limit
736 rl
.rlim_cur
= newMax
;
737 if (setrlimit(RLIMIT_NOFILE
, &rl
) == 0) {
738 PAssertOS(getrlimit(RLIMIT_NOFILE
, &rl
) == 0);
739 maxHandles
= rl
.rlim_cur
;
740 if (maxHandles
== newMax
) {
741 PTRACE(2, "PWLib\tNew maximum per-process file handles set to " << maxHandles
);
747 PTRACE(1, "PWLib\tCannot set per-process file handle limit to "
748 << newMax
<< " (is " << maxHandles
<< ") - check permissions");
753 PProcess::~PProcess()
757 // Don't wait for housekeeper to stop if Terminate() is called from it.
758 if (housekeepingThread
!= NULL
&& PThread::Current() != housekeepingThread
) {
759 housekeepingThread
->SetClosing();
761 housekeepingThread
->WaitForTermination();
762 delete housekeepingThread
;
766 PTRACE(5, "PWLib\tDestroyed process " << this);
769 BOOL
PProcess::PThreadKill(pthread_t id
, unsigned sig
)
771 PWaitAndSignal
m(threadMutex
);
773 if (!activeThreads
.Contains((unsigned)id
))
776 return pthread_kill(id
, sig
) == 0;
780 //////////////////////////////////////////////////////////////////////////////
784 // see InitialiseProcessThread()
788 void PThread::InitialiseProcessThread()
792 PX_origStackSize
= 0;
793 PX_threadId
= pthread_self();
794 PX_priority
= NormalPriority
;
797 #ifndef P_HAS_SEMAPHORES
798 PX_waitingSemaphore
= NULL
;
799 PX_WaitSemMutex
= MutexInitialiser
;
802 PX_suspendMutex
= MutexInitialiser
;
805 PAssertOS(socketpair(AF_INET
,SOCK_STREAM
,0,unblockPipe
) == 0);
807 PAssertOS(::pipe(unblockPipe
) == 0);
810 ((PProcess
*)this)->activeThreads
.DisallowDeleteObjects();
811 ((PProcess
*)this)->activeThreads
.SetAt((unsigned)PX_threadId
, this);
813 PX_firstTimeStart
= FALSE
;
815 traceBlockIndentLevel
= 0;
819 PThread::PThread(PINDEX stackSize
,
820 AutoDeleteFlag deletion
,
821 Priority priorityLevel
,
822 const PString
& name
)
825 autoDelete
= (deletion
== AutoDeleteThread
);
827 PAssert(stackSize
> 0, PInvalidParameter
);
828 PX_origStackSize
= stackSize
;
830 PX_priority
= priorityLevel
;
833 #ifndef P_HAS_SEMAPHORES
834 PX_waitingSemaphore
= NULL
;
835 PX_WaitSemMutex
= MutexInitialiser
;
838 PX_suspendMutex
= MutexInitialiser
;
841 PAssertOS(socketpair(AF_INET
,SOCK_STREAM
,0,unblockPipe
) == 0);
843 PAssertOS(::pipe(unblockPipe
) == 0);
845 PX_NewHandle("Thread unblock pipe", PMAX(unblockPipe
[0], unblockPipe
[1]));
847 // new thread is actually started the first time Resume() is called.
848 PX_firstTimeStart
= TRUE
;
850 traceBlockIndentLevel
= 0;
852 PTRACE(5, "PWLib\tCreated thread " << this << ' ' << threadName
);
858 if (PX_threadId
!= 0 && PX_threadId
!= pthread_self())
861 PAssertPTHREAD(::close
, (unblockPipe
[0]));
862 PAssertPTHREAD(::close
, (unblockPipe
[1]));
864 #ifndef P_HAS_SEMAPHORES
865 pthread_mutex_destroy(&PX_WaitSemMutex
);
868 // If the mutex was not locked, the unlock will fail */
869 pthread_mutex_trylock(&PX_suspendMutex
);
870 pthread_mutex_unlock(&PX_suspendMutex
);
871 pthread_mutex_destroy(&PX_suspendMutex
);
873 if (this != &PProcess::Current())
874 PTRACE(1, "PWLib\tDestroyed thread " << this << ' ' << threadName
<< "(id = " << ::hex
<< PX_threadId
<< ::dec
<< ")");
876 PProcessInstance
= NULL
;
880 void PThread::Restart()
885 pthread_attr_t threadAttr
;
886 pthread_attr_init(&threadAttr
);
887 pthread_attr_setdetachstate(&threadAttr
, PTHREAD_CREATE_DETACHED
);
891 // Set a decent (256K) stack size that won't eat all virtual memory
892 pthread_attr_setstacksize(&threadAttr
, 16*PTHREAD_STACK_MIN
);
895 Set realtime scheduling if our effective user id is root (only then is this
896 allowed) AND our priority is Highest.
897 As far as I can see, we could use either SCHED_FIFO or SCHED_RR here, it
899 I don't know if other UNIX OSs have SCHED_FIFO and SCHED_RR as well.
901 WARNING: a misbehaving thread (one that never blocks) started with Highest
902 priority can hang the entire machine. That is why root permission is
905 if ((geteuid() == 0) && (PX_priority
== HighestPriority
))
906 PAssertPTHREAD(pthread_attr_setschedpolicy
, (&threadAttr
, SCHED_FIFO
));
907 #elif defined(P_RTEMS)
908 pthread_attr_setstacksize(&threadAttr
, 2*PTHREAD_MINIMUM_STACK_SIZE
);
909 pthread_attr_setinheritsched(&threadAttr
, PTHREAD_EXPLICIT_SCHED
);
910 pthread_attr_setschedpolicy(&threadAttr
, SCHED_OTHER
);
911 struct sched_param sched_param
;
912 sched_param
.sched_priority
= 125; /* set medium priority */
913 pthread_attr_setschedparam(&threadAttr
, &sched_param
);
916 PProcess
& process
= PProcess::Current();
917 PINDEX newHighWaterMark
= 0;
918 static PINDEX highWaterMark
= 0;
920 // lock the thread list
921 process
.threadMutex
.Wait();
924 PAssertPTHREAD(pthread_create
, (&PX_threadId
, &threadAttr
, PX_ThreadStart
, this));
926 // put the thread into the thread list
927 process
.activeThreads
.SetAt((unsigned)PX_threadId
, this);
928 if (process
.activeThreads
.GetSize() > highWaterMark
)
929 newHighWaterMark
= highWaterMark
= process
.activeThreads
.GetSize();
931 // unlock the thread list
932 process
.threadMutex
.Signal();
934 PTRACE_IF(4, newHighWaterMark
> 0, "PWLib\tThread high water mark set: " << newHighWaterMark
);
937 if (PX_priority
== HighestPriority
) {
938 PTRACE(1, "set thread to have the highest priority (MACOSX)");
939 SetPriority(HighestPriority
);
945 void PX_SuspendSignalHandler(int)
947 PThread
* thread
= PThread::Current();
951 BOOL notResumed
= TRUE
;
954 notResumed
= ::read(thread
->unblockPipe
[0], &ch
, 1) < 0 && errno
== EINTR
;
955 #if !( defined(P_NETBSD) && defined(P_NO_CANCEL) )
956 pthread_testcancel();
962 void PThread::Suspend(BOOL susp
)
964 PAssertPTHREAD(pthread_mutex_lock
, (&PX_suspendMutex
));
966 // Check for start up condition, first time Resume() is called
967 if (PX_firstTimeStart
) {
971 if (PX_suspendCount
> 0)
973 if (PX_suspendCount
== 0) {
974 PX_firstTimeStart
= FALSE
;
979 PAssertPTHREAD(pthread_mutex_unlock
, (&PX_suspendMutex
));
983 #if defined(P_MACOSX) && (P_MACOSX <= 55)
984 // Suspend - warn the user with an Assertion
985 PAssertAlways("Cannot suspend threads on Mac OS X due to lack of pthread_kill()");
987 if (PPThreadKill(PX_threadId
, 0)) {
989 // if suspending, then see if already suspended
992 if (PX_suspendCount
== 1) {
993 if (PX_threadId
!= pthread_self()) {
994 signal(SUSPEND_SIG
, PX_SuspendSignalHandler
);
995 PPThreadKill(PX_threadId
, SUSPEND_SIG
);
998 PAssertPTHREAD(pthread_mutex_unlock
, (&PX_suspendMutex
));
999 PX_SuspendSignalHandler(SUSPEND_SIG
);
1000 return; // Mutex already unlocked
1005 // if resuming, then see if to really resume
1006 else if (PX_suspendCount
> 0) {
1008 if (PX_suspendCount
== 0)
1013 PAssertPTHREAD(pthread_mutex_unlock
, (&PX_suspendMutex
));
1018 void PThread::Resume()
1024 BOOL
PThread::IsSuspended() const
1026 if (PX_firstTimeStart
)
1032 PAssertPTHREAD(pthread_mutex_lock
, ((pthread_mutex_t
*)&PX_suspendMutex
));
1033 BOOL suspended
= PX_suspendCount
!= 0;
1034 PAssertPTHREAD(pthread_mutex_unlock
, ((pthread_mutex_t
*)&PX_suspendMutex
));
1039 void PThread::SetAutoDelete(AutoDeleteFlag deletion
)
1041 PAssert(deletion
!= AutoDeleteThread
|| this != &PProcess::Current(), PLogicError
);
1042 autoDelete
= deletion
== AutoDeleteThread
;
1046 // obtain thread priority of the main thread
1047 static unsigned long
1048 GetThreadBasePriority ()
1050 thread_basic_info_data_t threadInfo
;
1051 policy_info_data_t thePolicyInfo
;
1054 if (baseThread
== 0) {
1059 count
= THREAD_BASIC_INFO_COUNT
;
1060 thread_info (pthread_mach_thread_np (baseThread
), THREAD_BASIC_INFO
,
1061 (integer_t
*)&threadInfo
, &count
);
1063 switch (threadInfo
.policy
) {
1064 case POLICY_TIMESHARE
:
1065 count
= POLICY_TIMESHARE_INFO_COUNT
;
1066 thread_info(pthread_mach_thread_np (baseThread
),
1067 THREAD_SCHED_TIMESHARE_INFO
,
1068 (integer_t
*)&(thePolicyInfo
.ts
), &count
);
1069 return thePolicyInfo
.ts
.base_priority
;
1072 count
= POLICY_FIFO_INFO_COUNT
;
1073 thread_info(pthread_mach_thread_np (baseThread
),
1074 THREAD_SCHED_FIFO_INFO
,
1075 (integer_t
*)&(thePolicyInfo
.fifo
), &count
);
1076 if (thePolicyInfo
.fifo
.depressed
)
1077 return thePolicyInfo
.fifo
.depress_priority
;
1078 return thePolicyInfo
.fifo
.base_priority
;
1081 count
= POLICY_RR_INFO_COUNT
;
1082 thread_info(pthread_mach_thread_np (baseThread
),
1083 THREAD_SCHED_RR_INFO
,
1084 (integer_t
*)&(thePolicyInfo
.rr
), &count
);
1085 if (thePolicyInfo
.rr
.depressed
)
1086 return thePolicyInfo
.rr
.depress_priority
;
1087 return thePolicyInfo
.rr
.base_priority
;
1094 void PThread::SetPriority(Priority priorityLevel
)
1096 PX_priority
= priorityLevel
;
1098 #if defined(P_LINUX)
1102 struct sched_param sched_param
;
1104 if ((priorityLevel
== HighestPriority
) && (geteuid() == 0) ) {
1105 sched_param
.sched_priority
= sched_get_priority_min( SCHED_FIFO
);
1107 PAssertPTHREAD(pthread_setschedparam
, (PX_threadId
, SCHED_FIFO
, &sched_param
));
1109 else if (priorityLevel
!= HighestPriority
) {
1110 /* priority 0 is the only permitted value for the SCHED_OTHER scheduler */
1111 sched_param
.sched_priority
= 0;
1113 PAssertPTHREAD(pthread_setschedparam
, (PX_threadId
, SCHED_OTHER
, &sched_param
));
1117 #if defined(P_MACOSX)
1121 if (priorityLevel
== HighestPriority
) {
1122 /* get fixed priority */
1126 thread_extended_policy_data_t theFixedPolicy
;
1127 thread_precedence_policy_data_t thePrecedencePolicy
;
1128 long relativePriority
;
1130 theFixedPolicy
.timeshare
= false; // set to true for a non-fixed thread
1131 result
= thread_policy_set (pthread_mach_thread_np(PX_threadId
),
1132 THREAD_EXTENDED_POLICY
,
1133 (thread_policy_t
)&theFixedPolicy
,
1134 THREAD_EXTENDED_POLICY_COUNT
);
1135 if (result
!= KERN_SUCCESS
) {
1136 PTRACE(1, "thread_policy - Couldn't set thread as fixed priority.");
1141 // precedency policy's "importance" value is relative to
1142 // spawning thread's priority
1144 relativePriority
= 62 - GetThreadBasePriority();
1145 PTRACE(1, "relativePriority is " << relativePriority
<< " base priority is " << GetThreadBasePriority());
1147 thePrecedencePolicy
.importance
= relativePriority
;
1148 result
= thread_policy_set (pthread_mach_thread_np(PX_threadId
),
1149 THREAD_PRECEDENCE_POLICY
,
1150 (thread_policy_t
)&thePrecedencePolicy
,
1151 THREAD_PRECEDENCE_POLICY_COUNT
);
1152 if (result
!= KERN_SUCCESS
) {
1153 PTRACE(1, "thread_policy - Couldn't set thread priority.");
1161 PThread::Priority
PThread::GetPriority() const
1164 int schedulingPolicy
;
1165 struct sched_param schedParams
;
1167 PAssertPTHREAD(pthread_getschedparam
, (PX_threadId
, &schedulingPolicy
, &schedParams
));
1169 switch( schedulingPolicy
)
1176 return HighestPriority
;
1179 /* Unknown scheduler. We don't know what priority this thread has. */
1180 PTRACE(1, "PWLib\tPThread::GetPriority: unknown scheduling policy #" << schedulingPolicy
);
1184 return NormalPriority
; /* as good a guess as any */
1188 #ifndef P_HAS_SEMAPHORES
1189 void PThread::PXSetWaitingSemaphore(PSemaphore
* sem
)
1191 PAssertPTHREAD(pthread_mutex_lock
, (&PX_WaitSemMutex
));
1192 PX_waitingSemaphore
= sem
;
1193 PAssertPTHREAD(pthread_mutex_unlock
, (&PX_WaitSemMutex
));
1199 // GNU PTH threads version (used by NetBSD)
1200 // Taken from NetBSD pkg patches
1201 void PThread::Sleep(const PTimeInterval
& timeout
)
1204 PTime targetTime
= PTime() + timeout
;
1209 while (lastTime
< targetTime
) {
1210 P_timeval tval
= targetTime
- lastTime
;
1211 if (select(0, NULL
, NULL
, NULL
, tval
) < 0 && errno
!= EINTR
)
1214 pthread_testcancel();
1221 // Normal Posix threads version
1222 void PThread::Sleep(const PTimeInterval
& timeout
)
1225 PTime targetTime
= lastTime
+ timeout
;
1227 P_timeval tval
= targetTime
- lastTime
;
1228 if (select(0, NULL
, NULL
, NULL
, tval
) < 0 && errno
!= EINTR
)
1231 #if !( defined(P_NETBSD) && defined(P_NO_CANCEL) )
1232 pthread_testcancel();
1236 } while (lastTime
< targetTime
);
1240 void PThread::Yield()
1246 PThread
* PThread::Current()
1248 PProcess
& process
= PProcess::Current();
1249 process
.threadMutex
.Wait();
1250 PThread
* thread
= process
.activeThreads
.GetAt((unsigned)pthread_self());
1251 process
.threadMutex
.Signal();
1256 void PThread::Terminate()
1258 if (PX_origStackSize
<= 0)
1261 // don't use PThread::Current, as the thread may already not be in the
1262 // active threads list
1263 if (PX_threadId
== pthread_self()) {
1271 PTRACE(2, "PWLib\tForcing termination of thread " << (void *)this);
1274 WaitForTermination(20);
1276 #if !defined(P_HAS_SEMAPHORES) && !defined(P_HAS_NAMED_SEMAPHORES)
1277 PAssertPTHREAD(pthread_mutex_lock
, (&PX_WaitSemMutex
));
1278 if (PX_waitingSemaphore
!= NULL
) {
1279 PAssertPTHREAD(pthread_mutex_lock
, (&PX_waitingSemaphore
->mutex
));
1280 PX_waitingSemaphore
->queuedLocks
--;
1281 PAssertPTHREAD(pthread_mutex_unlock
, (&PX_waitingSemaphore
->mutex
));
1282 PX_waitingSemaphore
= NULL
;
1284 PAssertPTHREAD(pthread_mutex_unlock
, (&PX_WaitSemMutex
));
1287 #if ( defined(P_NETBSD) && defined(P_NO_CANCEL) )
1288 PPThreadKill(PX_threadId
,SIGKILL
);
1291 pthread_cancel(PX_threadId
);
1297 BOOL
PThread::IsTerminated() const
1299 pthread_t id
= PX_threadId
;
1300 return (id
== 0) || !PPThreadKill(id
, 0);
1304 void PThread::WaitForTermination() const
1306 if (this == Current()) {
1307 PTRACE(2, "WaitForTermination short circuited");
1311 PXAbortBlock(); // this assist in clean shutdowns on some systems
1313 while (!IsTerminated()) {
1314 Sleep(10); // sleep for 10ms. This slows down the busy loop removing 100%
1315 // CPU usage and also yeilds so other threads can run.
1320 BOOL
PThread::WaitForTermination(const PTimeInterval
& maxWait
) const
1322 if (this == Current()) {
1323 PTRACE(2, "WaitForTermination(t) short circuited");
1327 PTRACE(6, "PWLib\tWaitForTermination(" << maxWait
<< ')');
1329 PXAbortBlock(); // this assist in clean shutdowns on some systems
1330 PTimer timeout
= maxWait
;
1331 while (!IsTerminated()) {
1334 Sleep(10); // sleep for 10ms. This slows down the busy loop removing 100%
1335 // CPU usage and also yeilds so other threads can run.
1341 void * PThread::PX_ThreadStart(void * arg
)
1343 PThread
* thread
= (PThread
*)arg
;
1344 //don't need to detach the the thread, it was created in the PTHREAD_CREATE_DETACHED state
1345 // Added this to guarantee that the thread creation (PThread::Restart)
1346 // has completed before we start the thread. Then the PX_threadId has
1348 pthread_mutex_lock(&thread
->PX_suspendMutex
);
1349 thread
->SetThreadName(thread
->GetThreadName());
1350 pthread_mutex_unlock(&thread
->PX_suspendMutex
);
1352 // make sure the cleanup routine is called when the thread exits
1353 pthread_cleanup_push(&PThread::PX_ThreadEnd
, arg
);
1355 PTRACE(5, "PWLib\tStarted thread " << thread
<< ' ' << thread
->threadName
);
1357 // now call the the thread main routine
1360 // execute the cleanup routine
1361 pthread_cleanup_pop(1);
1367 void PThread::PX_ThreadEnd(void * arg
)
1369 PProcess
& process
= PProcess::Current();
1370 process
.threadMutex
.Wait();
1372 PThread
* thread
= (PThread
*)arg
;
1373 pthread_t id
= thread
->GetThreadId();
1375 // Don't know why, but pthreads under Linux at least can call this function
1376 // multiple times! Probably a bug, but we have to allow for it.
1377 process
.threadMutex
.Signal();
1378 PTRACE(2, "PWLib\tAttempted to multiply end thread " << thread
<< " ThreadID=" << (void *)id
);
1382 // remove this thread from the active thread list
1383 process
.activeThreads
.SetAt((unsigned)id
, NULL
);
1385 // delete the thread if required, note this is done this way to avoid
1386 // a race condition, the thread ID cannot be zeroed before the if!
1387 if (thread
->autoDelete
) {
1388 thread
->PX_threadId
= 0; // Prevent terminating terminated thread
1389 process
.threadMutex
.Signal();
1390 PTRACE(5, "PWLib\tEnded thread " << thread
<< ' ' << thread
->threadName
);
1392 /* It is now safe to delete this thread. Note that this thread
1393 is deleted after the process.threadMutex.Signal(), which means
1394 PWaitAndSignal(process.threadMutex) could not be used */
1398 thread
->PX_threadId
= 0;
1399 PString threadName
= thread
->threadName
;
1400 process
.threadMutex
.Signal();
1401 PTRACE(5, "PWLib\tEnded thread " << thread
<< ' ' << threadName
);
1405 int PThread::PXBlockOnIO(int handle
, int type
, const PTimeInterval
& timeout
)
1407 PTRACE(7, "PWLib\tPThread::PXBlockOnIO(" << handle
<< ',' << type
<< ')');
1409 if ((handle
< 0) || (handle
>= PProcess::Current().GetMaxHandles())) {
1410 PTRACE(2, "PWLib\tAttempt to use illegal handle in PThread::PXBlockOnIO, handle=" << handle
);
1415 // make sure we flush the buffer before doing a write
1418 P_fd_set exception_fds
;
1423 case PChannel::PXReadBlock
:
1424 case PChannel::PXAcceptBlock
:
1427 exception_fds
.Zero();
1429 case PChannel::PXWriteBlock
:
1432 exception_fds
.Zero();
1434 case PChannel::PXConnectBlock
:
1437 exception_fds
= handle
;
1440 PAssertAlways(PLogicError
);
1444 // include the termination pipe into all blocking I/O functions
1445 read_fds
+= unblockPipe
[0];
1447 P_timeval tval
= timeout
;
1448 retval
= ::select(PMAX(handle
, unblockPipe
[0])+1,
1449 read_fds
, write_fds
, exception_fds
, tval
);
1450 } while (retval
< 0 && errno
== EINTR
);
1452 if ((retval
== 1) && read_fds
.IsPresent(unblockPipe
[0])) {
1454 ::read(unblockPipe
[0], &ch
, 1);
1457 PTRACE(6, "PWLib\tUnblocked I/O fd=" << unblockPipe
[0]);
1463 void PThread::PXAbortBlock() const
1466 ::write(unblockPipe
[1], &ch
, 1);
1467 PTRACE(6, "PWLib\tUnblocking I/O fd=" << unblockPipe
[0] << " thread=" << GetThreadName());
1471 ///////////////////////////////////////////////////////////////////////////////
1473 PSemaphore::PSemaphore(PXClass pxc
)
1477 // these should never be used, as this constructor is
1478 // only used for PMutex and PSyncPoint and they have their
1479 // own copy constructors
1481 initialVar
= maxCountVar
= 0;
1483 if(pxClass
== PXSemaphore
) {
1484 #if defined(P_HAS_SEMAPHORES)
1485 /* call sem_init, otherwise sem_destroy fails*/
1486 PAssertPTHREAD(sem_init
, (&semId
, 0, 0));
1487 #elif defined(P_HAS_NAMED_SEMAPHORES)
1488 semId
= CreateSem(0);
1490 currentCount
= maximumCount
= 0;
1492 pthread_mutex_init(&mutex
, NULL
);
1493 pthread_cond_init(&condVar
, NULL
);
1499 PSemaphore::PSemaphore(unsigned initial
, unsigned maxCount
)
1501 pxClass
= PXSemaphore
;
1503 initialVar
= initial
;
1504 maxCountVar
= maxCount
;
1506 #if defined(P_HAS_SEMAPHORES)
1507 PAssertPTHREAD(sem_init
, (&semId
, 0, initial
));
1508 #elif defined(P_HAS_NAMED_SEMAPHORES)
1509 semId
= CreateSem(initialVar
);
1511 PAssertPTHREAD(pthread_mutex_init
, (&mutex
, NULL
));
1512 PAssertPTHREAD(pthread_cond_init
, (&condVar
, NULL
));
1514 PAssert(maxCount
> 0, "Invalid semaphore maximum.");
1515 if (initial
> maxCount
)
1518 currentCount
= initial
;
1519 maximumCount
= maxCount
;
1525 PSemaphore::PSemaphore(const PSemaphore
& sem
)
1527 pxClass
= sem
.GetSemClass();
1529 initialVar
= sem
.GetInitial();
1530 maxCountVar
= sem
.GetMaxCount();
1532 if(pxClass
== PXSemaphore
) {
1533 #if defined(P_HAS_SEMAPHORES)
1534 PAssertPTHREAD(sem_init
, (&semId
, 0, initialVar
));
1535 #elif defined(P_HAS_NAMED_SEMAPHORES)
1536 semId
= CreateSem(initialVar
);
1538 PAssertPTHREAD(pthread_mutex_init
, (&mutex
, NULL
));
1539 PAssertPTHREAD(pthread_cond_init
, (&condVar
, NULL
));
1541 PAssert(maxCountVar
> 0, "Invalid semaphore maximum.");
1542 if (initialVar
> maxCountVar
)
1543 initialVar
= maxCountVar
;
1545 currentCount
= initialVar
;
1546 maximumCount
= maxCountVar
;
1552 PSemaphore::~PSemaphore()
1554 if(pxClass
== PXSemaphore
) {
1555 #if defined(P_HAS_SEMAPHORES)
1556 PAssertPTHREAD(sem_destroy
, (&semId
));
1557 #elif defined(P_HAS_NAMED_SEMAPHORES)
1558 PAssertPTHREAD(sem_close
, (semId
));
1560 PAssert(queuedLocks
== 0, "Semaphore destroyed with queued locks");
1561 PAssertPTHREAD(pthread_mutex_destroy
, (&mutex
));
1562 PAssertPTHREAD(pthread_cond_destroy
, (&condVar
));
1567 #if defined(P_HAS_NAMED_SEMAPHORES)
1568 sem_t
* PSemaphore::CreateSem(unsigned initialValue
)
1572 // Since sem_open and sem_unlink are two operations, there is a small
1573 // window of opportunity that two simultaneous accesses may return
1574 // the same semaphore. Therefore, the static mutex is used to
1575 // prevent this, even if the chances are small
1576 static pthread_mutex_t semCreationMutex
= PTHREAD_MUTEX_INITIALIZER
;
1577 PAssertPTHREAD(pthread_mutex_lock
, (&semCreationMutex
));
1579 sem_unlink("/pwlib_sem");
1580 sem
= sem_open("/pwlib_sem", (O_CREAT
| O_EXCL
), 700, initialValue
);
1582 PAssertPTHREAD(pthread_mutex_unlock
, (&semCreationMutex
));
1584 PAssert(((int)sem
!= SEM_FAILED
), "Couldn't create named semaphore");
1589 void PSemaphore::Wait()
1591 #if defined(P_HAS_SEMAPHORES)
1592 PAssertPTHREAD(sem_wait
, (&semId
));
1593 #elif defined(P_HAS_NAMED_SEMAPHORES)
1594 PAssertPTHREAD(sem_wait
, (semId
));
1596 PAssertPTHREAD(pthread_mutex_lock
, (&mutex
));
1599 PThread::Current()->PXSetWaitingSemaphore(this);
1601 while (currentCount
== 0) {
1602 int err
= pthread_cond_wait(&condVar
, &mutex
);
1603 PAssert(err
== 0 || err
== EINTR
, psprintf("wait error = %i", err
));
1606 PThread::Current()->PXSetWaitingSemaphore(NULL
);
1611 PAssertPTHREAD(pthread_mutex_unlock
, (&mutex
));
1616 BOOL
PSemaphore::Wait(const PTimeInterval
& waitTime
)
1618 if (waitTime
== PMaxTimeInterval
) {
1623 // create absolute finish time
1625 finishTime
+= waitTime
;
1627 #if defined(P_HAS_SEMAPHORES)
1628 #ifdef P_HAS_SEMAPHORES_XPG6
1629 // use proper timed spinlocks if supported.
1630 // http://www.opengroup.org/onlinepubs/007904975/functions/sem_timedwait.html
1632 struct timespec absTime
;
1633 absTime
.tv_sec
= finishTime
.GetTimeInSeconds();
1634 absTime
.tv_nsec
= finishTime
.GetMicrosecond() * 1000;
1636 if (sem_timedwait(&semId
, &absTime
) == 0) {
1644 // loop until timeout, or semaphore becomes available
1645 // don't use a PTimer, as this causes the housekeeping
1646 // thread to get very busy
1648 if (sem_trywait(&semId
) == 0)
1651 #if defined(P_LINUX)
1652 // sched_yield in a tight loop is bad karma
1653 // for the linux scheduler: http://www.ussg.iu.edu/hypermail/linux/kernel/0312.2/1127.html
1654 PThread::Current()->Sleep(10);
1658 } while (PTime() < finishTime
);
1663 #elif defined(P_HAS_NAMED_SEMAPHORES)
1665 if(sem_trywait(semId
) == 0)
1667 PThread::Current()->Sleep(10);
1668 } while (PTime() < finishTime
);
1673 struct timespec absTime
;
1674 absTime
.tv_sec
= finishTime
.GetTimeInSeconds();
1675 absTime
.tv_nsec
= finishTime
.GetMicrosecond() * 1000;
1677 PAssertPTHREAD(pthread_mutex_lock
, (&mutex
));
1679 PThread
* thread
= PThread::Current();
1680 thread
->PXSetWaitingSemaphore(this);
1684 while (currentCount
== 0) {
1685 int err
= pthread_cond_timedwait(&condVar
, &mutex
, &absTime
);
1686 if (err
== ETIMEDOUT
) {
1691 PAssert(err
== 0 || err
== EINTR
, psprintf("timed wait error = %i", err
));
1694 thread
->PXSetWaitingSemaphore(NULL
);
1700 PAssertPTHREAD(pthread_mutex_unlock
, ((pthread_mutex_t
*)&mutex
));
1707 void PSemaphore::Signal()
1709 #if defined(P_HAS_SEMAPHORES)
1710 PAssertPTHREAD(sem_post
, (&semId
));
1711 #elif defined(P_HAS_NAMED_SEMAPHORES)
1712 PAssertPTHREAD(sem_post
, (semId
));
1714 PAssertPTHREAD(pthread_mutex_lock
, (&mutex
));
1716 if (currentCount
< maximumCount
)
1719 if (queuedLocks
> 0)
1720 PAssertPTHREAD(pthread_cond_signal
, (&condVar
));
1722 PAssertPTHREAD(pthread_mutex_unlock
, (&mutex
));
1727 BOOL
PSemaphore::WillBlock() const
1729 #if defined(P_HAS_SEMAPHORES)
1730 if (sem_trywait((sem_t
*)&semId
) != 0) {
1731 PAssertOS(errno
== EAGAIN
|| errno
== EINTR
);
1734 PAssertPTHREAD(sem_post
, ((sem_t
*)&semId
));
1736 #elif defined(P_HAS_NAMED_SEMAPHORES)
1737 if (sem_trywait(semId
) != 0) {
1738 PAssertOS(errno
== EAGAIN
|| errno
== EINTR
);
1741 PAssertPTHREAD(sem_post
, (semId
));
1744 return currentCount
== 0;
1748 PTimedMutex::PTimedMutex()
1749 // : PSemaphore(PXMutex)
1751 #if P_HAS_RECURSIVE_MUTEX
1752 pthread_mutexattr_t attr
;
1753 PAssertPTHREAD(pthread_mutexattr_init
, (&attr
));
1755 PAssertPTHREAD(pthread_mutexattr_settype
, (&attr
,
1756 #if P_HAS_RECURSIVE_MUTEX == 2
1757 PTHREAD_MUTEX_RECURSIVE
1759 PTHREAD_MUTEX_RECURSIVE_NP
1763 PAssertPTHREAD(pthread_mutex_init
, (&mutex
, &attr
));
1764 PAssertPTHREAD(pthread_mutexattr_destroy
, (&attr
));
1766 PAssertPTHREAD(pthread_mutex_init
, (&mutex
, NULL
));
1770 PTimedMutex::PTimedMutex(const PTimedMutex
& /*mut*/)
1771 // : PSemaphore(PXMutex)
1773 #if P_HAS_RECURSIVE_MUTEX
1774 pthread_mutexattr_t attr
;
1775 PAssertPTHREAD(pthread_mutexattr_init
, (&attr
));
1776 PAssertPTHREAD(pthread_mutexattr_settype
, (&attr
, PTHREAD_MUTEX_RECURSIVE_NP
));
1777 PAssertPTHREAD(pthread_mutex_init
, (&mutex
, &attr
));
1778 PAssertPTHREAD(pthread_mutexattr_destroy
, (&attr
));
1780 pthread_mutex_init(&mutex
, NULL
);
1784 PTimedMutex::~PTimedMutex()
1786 int result
= pthread_mutex_destroy(&mutex
);
1788 while ((result
== EBUSY
) && (i
++ < 20)) {
1789 pthread_mutex_unlock(&mutex
);
1790 result
= pthread_mutex_destroy(&mutex
);
1793 PAssert((result
== 0), "Error destroying mutex");
1797 void PTimedMutex::Wait()
1799 pthread_t currentThreadId
= pthread_self();
1801 #if P_HAS_RECURSIVE_MUTEX == 0
1803 // if the mutex is already acquired by this thread,
1804 // then just increment the lock count
1805 if (pthread_equal(lockerId
, currentThreadId
)) {
1806 // Note this does not need a lock as it can only be touched by the thread
1807 // which already has the mutex locked.
1813 // acquire the lock for real
1814 PAssertPTHREAD(pthread_mutex_lock
, (&mutex
));
1816 #if P_HAS_RECURSIVE_MUTEX == 0
1817 PAssert((lockerId
== (pthread_t
)-1) && (lockCount
.IsZero()),
1818 "PMutex acquired whilst locked by another thread");
1819 // Note this is protected by the mutex itself only the thread with
1820 // the lock can alter it.
1823 lockerId
= currentThreadId
;
1827 BOOL
PTimedMutex::Wait(const PTimeInterval
& waitTime
)
1829 // get the current thread ID
1830 pthread_t currentThreadId
= pthread_self();
1832 // if waiting indefinitely, then do so
1833 if (waitTime
== PMaxTimeInterval
) {
1835 lockerId
= currentThreadId
;
1839 #if P_HAS_RECURSIVE_MUTEX == 0
1840 // if we already have the mutex, return immediately
1841 if (pthread_equal(lockerId
, currentThreadId
)) {
1842 // Note this does not need a lock as it can only be touched by the thread
1843 // which already has the mutex locked.
1849 // create absolute finish time
1851 finishTime
+= waitTime
;
1855 struct timespec absTime
;
1856 absTime
.tv_sec
= finishTime
.GetTimeInSeconds();
1857 absTime
.tv_nsec
= finishTime
.GetMicrosecond() * 1000;
1859 if (pthread_mutex_timedlock(&mutex
, &absTime
) != 0)
1862 #if P_HAS_RECURSIVE_MUTEX == 0
1863 PAssert((lockerId
== (pthread_t
)-1) && (lockCount
.IsZero()),
1864 "PMutex acquired whilst locked by another thread");
1867 // Note this is protected by the mutex itself only the thread with
1868 // the lock can alter it.
1869 lockerId
= currentThreadId
;
1872 #else // P_PTHREADS_XPG6
1875 if (pthread_mutex_trylock(&mutex
) == 0) {
1876 #if P_HAS_RECURSIVE_MUTEX == 0
1877 PAssert((lockerId
== (pthread_t
)-1) && (lockCount
.IsZero()),
1878 "PMutex acquired whilst locked by another thread");
1880 lockerId
= currentThreadId
;
1885 PThread::Current()->Sleep(10); // sleep for 10ms
1886 } while (PTime() < finishTime
);
1890 #endif // P_PTHREADS_XPG6
1894 void PTimedMutex::Signal()
1896 #if P_HAS_RECURSIVE_MUTEX == 0
1897 if (!pthread_equal(lockerId
, pthread_self())) {
1898 PAssertAlways("PMutex signal failed - no matching wait or signal by wrong thread");
1902 // if lock was recursively acquired, then decrement the counter
1903 // Note this does not need a separate lock as it can only be touched by the thread
1904 // which already has the mutex locked.
1905 if (!lockCount
.IsZero()) {
1910 // otherwise mark mutex as available
1911 lockerId
= (pthread_t
)-1;
1915 PAssertPTHREAD(pthread_mutex_unlock
, (&mutex
));
1919 BOOL
PTimedMutex::WillBlock() const
1921 #if P_HAS_RECURSIVE_MUTEX == 0
1922 pthread_t currentThreadId
= pthread_self();
1923 if (currentThreadId
== lockerId
)
1927 pthread_mutex_t
* mp
= (pthread_mutex_t
*)&mutex
;
1928 if (pthread_mutex_trylock(mp
) != 0)
1931 PAssertPTHREAD(pthread_mutex_unlock
, (mp
));
1936 PSyncPoint::PSyncPoint()
1937 : PSemaphore(PXSyncPoint
)
1939 PAssertPTHREAD(pthread_mutex_init
, (&mutex
, NULL
));
1940 PAssertPTHREAD(pthread_cond_init
, (&condVar
, NULL
));
1944 PSyncPoint::PSyncPoint(const PSyncPoint
&)
1945 : PSemaphore(PXSyncPoint
)
1947 PAssertPTHREAD(pthread_mutex_init
, (&mutex
, NULL
));
1948 PAssertPTHREAD(pthread_cond_init
, (&condVar
, NULL
));
1952 PSyncPoint::~PSyncPoint()
1954 PAssertPTHREAD(pthread_mutex_destroy
, (&mutex
));
1955 PAssertPTHREAD(pthread_cond_destroy
, (&condVar
));
1958 void PSyncPoint::Wait()
1960 PAssertPTHREAD(pthread_mutex_lock
, (&mutex
));
1961 while (signalCount
== 0)
1962 pthread_cond_wait(&condVar
, &mutex
);
1964 PAssertPTHREAD(pthread_mutex_unlock
, (&mutex
));
1968 BOOL
PSyncPoint::Wait(const PTimeInterval
& waitTime
)
1970 PAssertPTHREAD(pthread_mutex_lock
, (&mutex
));
1973 finishTime
+= waitTime
;
1974 struct timespec absTime
;
1975 absTime
.tv_sec
= finishTime
.GetTimeInSeconds();
1976 absTime
.tv_nsec
= finishTime
.GetMicrosecond() * 1000;
1979 while (signalCount
== 0) {
1980 err
= pthread_cond_timedwait(&condVar
, &mutex
, &absTime
);
1981 if (err
== 0 || err
== ETIMEDOUT
)
1984 PAssertOS(err
== EINTR
&& errno
== EINTR
);
1990 PAssertPTHREAD(pthread_mutex_unlock
, (&mutex
));
1996 void PSyncPoint::Signal()
1998 PAssertPTHREAD(pthread_mutex_lock
, (&mutex
));
2000 PAssertPTHREAD(pthread_cond_signal
, (&condVar
));
2001 PAssertPTHREAD(pthread_mutex_unlock
, (&mutex
));
2005 BOOL
PSyncPoint::WillBlock() const
2007 return signalCount
== 0;