Fixed build on MacOSX
[pwlib.git] / src / ptlib / unix / tlibthrd.cxx
blob2303514a3002a990c11fb2a76beffe7c9d6e088b
1 /*
2 * tlibthrd.cxx
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
18 * under the License.
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): ______________________________________.
29 * $Log$
30 * Revision 1.173 2007/09/05 11:58:47 csoutheren
31 * Fixed build on MacOSX
33 * Revision 1.170 2007/08/17 07:29:21 csoutheren
34 * Fix build on MacOSX
36 * Revision 1.169 2007/08/17 07:05:13 csoutheren
37 * Fix problem with false asserts based on mutex locking
39 * Revision 1.168 2007/08/17 05:29:19 csoutheren
40 * Add field to Linux showing locking thread to assist in debugging
42 * Revision 1.167 2007/07/19 08:11:47 csoutheren
43 * Fix problem with hex in log stream
45 * Revision 1.166 2007/07/06 02:12:14 csoutheren
46 * Add extra memory leak debugging on Linux
47 * Remove compile warnings
49 * Revision 1.165 2007/05/01 10:20:44 csoutheren
50 * Applied 1703617 - Prevention of application deadlock caused by too many timers
51 * Thanks to Fabrizio Ammollo
53 * Revision 1.164 2006/10/23 01:15:16 csoutheren
54 * Revert to revision 1.153 to fix crash problem with SIP connections
56 * Revision 1.153 2006/06/25 21:46:38 dereksmithies
57 * Thanks to Paul Nader for this fix which fixes thread cleanup
58 * issues on SMP machines. Good find.
60 * Revision 1.152 2006/03/01 08:29:33 csoutheren
61 * Applied patch #1439578 PTrace / PThread::PX_ThreadEnd deadlock fix
62 * Thanks to Hannes Friederich
64 * Revision 1.151 2006/01/29 22:35:47 csoutheren
65 * Added fix for thread termination problems on SMP machines
66 * Thanks to Derek Smithies
68 * Revision 1.150 2005/12/05 22:35:24 csoutheren
69 * Only assert in PTimedMutex destructor if _DEBUG is enabled
71 * Revision 1.149 2005/12/04 22:07:26 csoutheren
72 * Fixed uninitialised variable
74 * Revision 1.148 2005/12/01 00:55:19 csoutheren
75 * Removed chance of endless loop in PTimedMutex destructor
77 * Revision 1.147 2005/11/25 00:06:12 csoutheren
78 * Applied patch #1364593 from Hannes Friederich
79 * Also changed so PTimesMutex is no longer descended from PSemaphore on
80 * non-Windows platforms
82 * Revision 1.146 2005/11/22 22:38:36 dsandras
83 * Removed Assert that was causing problem if the mutex is locked when being
84 * destroyed.
86 * Revision 1.145 2005/11/18 22:26:07 dsandras
87 * Removed a few more CONST's to match with previous commit and fix permanent
88 * deadlock.
90 * Revision 1.144 2005/11/14 22:41:53 csoutheren
91 * Reverted Wait and Signal to non-const - there is no way we can guarantee that all
92 * descendant classes everywhere will be changed over, so we have to keep the
93 * original API
95 * Revision 1.143 2005/11/04 09:44:30 csoutheren
96 * Applied patch #1324589
97 * Removed race conditions in PSemaphore and thread handling
98 * Thanks to Frederic Heem
100 * Revision 1.142 2005/11/04 06:56:10 csoutheren
101 * Added new class PSync as abstract base class for all mutex/sempahore classes
102 * Changed PCriticalSection to use Wait/Signal rather than Enter/Leave
103 * Changed Wait/Signal to be const member functions
104 * Renamed PMutex to PTimedMutex and made PMutex synonym for PCriticalSection.
105 * This allows use of very efficient mutex primitives in 99% of cases where timed waits
106 * are not needed
108 * Revision 1.141 2005/07/22 04:19:18 csoutheren
109 * Removed redundant check of thread ID introduced in last patch
110 * Removed race condition in thread shutdown found by Derek Smithies
112 * Revision 1.140 2005/07/21 13:04:11 csoutheren
113 * Removed race condition where activeThreads list does not contain
114 * thread until some time after thread is started. Fixed by moving
115 * list insertion to immediately after pthread_create, and using lock
117 * Revision 1.139 2005/07/21 00:09:08 csoutheren
118 * Added workaround for braindead behaviour of pthread_kill
119 * Thanks to "martin martin" <acevedoma@hotmail.com>
121 * Revision 1.138 2005/05/03 11:58:46 csoutheren
122 * Fixed various problems reported by valgrind
123 * Thanks to Paul Cadach
125 * Revision 1.137 2005/01/21 21:25:19 csoutheren
126 * Removed incorrect return in PThread::WaitForTermination
128 * Revision 1.136 2005/01/16 23:00:37 csoutheren
129 * Fixed problem when calling WaitForTermination from within the same thread
131 * Revision 1.135 2004/12/21 06:30:55 csoutheren
132 * Added explicit stack size for pthreads to minimise VM usage, thanks to Diana Cionoiu
134 * Revision 1.134 2004/09/02 07:55:44 csoutheren
135 * Added extra PXAbortBlock to WaitForTermination to assist in terminaing
136 * threads under certain conditions
138 * Revision 1.133 2004/06/24 11:29:44 csoutheren
139 * Changed to use pthread_mutex_timedlock for more efficient mutex wait operations
140 * Thanks to Michal Zygmuntowicz
142 * Revision 1.132 2004/06/01 07:42:20 csoutheren
143 * Restored memory allocation checking
144 * Added configure flag to enable, thanks to Derek Smithies
146 * Revision 1.131 2004/05/21 00:49:16 csoutheren
147 * Added PreShutdown to ~PProcess
149 * Revision 1.130 2004/04/27 04:36:47 rjongbloed
150 * Fixed occassional crash on exit due to level 5 trace in PProcess
151 * destructor that needs an undestructed PProcess.
152 * Added some more logging for unblocking threads.
154 * Revision 1.129 2004/04/12 03:35:27 csoutheren
155 * Fixed problems with non-recursuve mutexes and critical sections on
156 * older compilers and libc
158 * Revision 1.128 2004/04/12 00:58:45 csoutheren
159 * Fixed PAtomicInteger on Linux, and modified PMutex to use it
161 * Revision 1.127 2004/04/11 07:58:08 csoutheren
162 * Added configure.in check for recursive mutexes, and changed implementation
163 * without recursive mutexes to use PCriticalSection or atomic word structs
165 * Revision 1.126 2004/03/24 02:37:04 csoutheren
166 * Fixed problem with incorrect usage of sem_timedwait
168 * Revision 1.125 2004/03/23 04:56:23 csoutheren
169 * Added patches to use XPG6 threading under Linux if available
170 * Thanks to Matthew Hodgson
172 * Revision 1.124 2004/02/01 11:23:16 dsandras
173 * Reverted previous Change and removed Yield call from Current (). Fix from Christian Meder <chris@onestepahead.de>. Thanks for your help, Christian!
175 * Revision 1.123 2004/01/31 13:49:18 dominance
176 * Added 2.6 performance fix as proposed by Christian Meder <chris@onestepahead.de>.
178 * Revision 1.122 2003/09/17 09:02:15 csoutheren
179 * Removed memory leak detection code
181 * Revision 1.121 2003/05/16 17:40:55 shawn
182 * On Mac OS X, thread with the highest priority should use fixed priority
183 * scheduling policy. This avoids starvation caused by desktop activity.
185 * Revision 1.120 2003/05/02 00:58:40 dereks
186 * Add test for linux at the end of PMutex::Signal. Thanks Robert!
188 * Revision 1.119 2003/05/02 00:39:11 dereks
189 * Changes to make threading work on Redhat 9
191 * Revision 1.118 2003/04/24 12:03:13 rogerh
192 * Calling pthread_mutex_unlock() on a mutex which is not locked can be
193 * considered an error. NetBSD now enforce this error so we need to quickly
194 * try locking the mutex before unlocking it in ~PThread and ~PSemaphore.
196 * Revision 1.117 2003/04/08 03:29:31 robertj
197 * Fixed IsSuspeneded() so returns TRUE if thread not started yet, this makes
198 * it the same as the Win32 semantics.
200 * Revision 1.116 2003/03/10 15:37:00 rogerh
201 * fix IsTerminated() function.
203 * Revision 1.115 2003/03/07 00:07:15 robertj
204 * Fixed Mac OS X patch which broke every other platform.
206 * Revision 1.114 2003/03/06 08:58:48 rogerh
207 * P_MACOSX now carries the OSRELEASE. Use this to enable better threads
208 * support on Darwin 6.4. Submitted by Shawn.
210 * Revision 1.113 2003/02/20 23:32:00 robertj
211 * More RTEMS support patches, thanks Sebastian Meyer.
213 * Revision 1.112 2003/01/24 10:21:06 robertj
214 * Fixed issues in RTEMS support, thanks Vladimir Nesic
216 * Revision 1.111 2003/01/20 10:13:18 rogerh
217 * NetBSD thread changes
219 * Revision 1.110 2003/01/20 10:05:46 rogerh
220 * NetBSD thread changes
222 * Revision 1.109 2003/01/08 08:47:51 rogerh
223 * Add new Sleep() function for GNU PTH threads.
224 * Taken from NetBSD's package which uses PTH.
225 * Note: I am not sure this works correctly.
227 * Revision 1.108 2003/01/06 18:49:15 rogerh
228 * Back out pthead_kill to pthread_cancel change on NetBSD
230 * Revision 1.107 2002/12/11 05:39:26 robertj
231 * Added logging for file handle changes.
232 * Fixd bug where internal maxHandles not set when increased.
234 * Revision 1.106 2002/12/02 03:57:18 robertj
235 * More RTEMS support patches, thank you Vladimir Nesic.
237 * Revision 1.105 2002/11/22 10:14:07 robertj
238 * QNX port, thanks Xiaodan Tang
240 * Revision 1.104 2002/11/04 16:01:27 rogerh
241 * Using pthread_cancel and not pthread_kill with SIGKILL to terminate a thread
242 * On FreeBSD the thread does not have a handler for SIGKILL, it passes it up
243 * to the main process which gets killed! Assume the other BSDs are the same.
245 * Revision 1.103 2002/10/24 00:40:56 robertj
246 * Put back ability to terminate a thread from that threads context (removed
247 * in revision 1.101) but requires that destructor not do so.
248 * Changed pipe close to allow for possible EINTR, and retry close.
250 * Revision 1.102 2002/10/24 00:25:13 robertj
251 * Changed high load thread problem fix from the termination function to start
252 * function to finally, once and for all (I hope!) fix the race condition.
254 * Revision 1.101 2002/10/23 14:56:22 craigs
255 * Fixed problem with pipe leak under some circumstances
257 * Revision 1.100 2002/10/23 04:29:32 robertj
258 * Improved debugging for thread create/start/stop/destroy.
259 * Fixed race condition bug if auto-delete thread starts and completes before
260 * pthread_create returns, PX_threadId is not set yet!
262 * Revision 1.99 2002/10/22 07:42:52 robertj
263 * Added extra debugging for file handle and thread leak detection.
265 * Revision 1.98 2002/10/18 03:05:39 robertj
266 * Fixed thread leak caused by fixing the thread crash a few revisions back,
267 * caused by strange pthreads behaviour, at least under Linux.
269 * Revision 1.97 2002/10/17 13:44:27 robertj
270 * Port to RTEMS, thanks Vladimir Nesic.
272 * Revision 1.96 2002/10/17 12:57:24 robertj
273 * Added ability to increase maximum file handles on a process.
275 * Revision 1.95 2002/10/16 11:26:29 rogerh
276 * Add missing include. Noticed by Matthias on the GnomeMeeting IRC
278 * Revision 1.94 2002/10/10 03:09:48 robertj
279 * Fixed high load race condition when starting threads.
281 * Revision 1.93 2002/10/05 05:22:43 robertj
282 * Fixed adding GetThreadId() function.
284 * Revision 1.92 2002/10/01 06:27:48 robertj
285 * Added bullet proofing against possible EINTR error returns on all pthread
286 * functions when under heavy load. Linux really should NOT do this, but ...
288 * Revision 1.91 2002/09/04 03:14:18 robertj
289 * Backed out changes submitted by Martin Froehlich as they do not appear to
290 * actually do anything other than add a sychronisation point. The variables
291 * the patches intended to protect were already protected.
292 * Fixed bug where if a PMutex was signalled by a thread that did not have it
293 * locked, it would assert but continue to alter PMutex variables such that
294 * a deadlock or crash is likely.
296 * Revision 1.90 2002/08/29 01:50:40 robertj
297 * Changed the pthread_create so does retries if get EINTR or EAGAIN errors
298 * which indicate a (possibly) temporary resource limit.
299 * Enabled and adjusted tracing.
301 * Revision 1.89 2002/08/22 13:05:57 craigs
302 * Fixed problems with mutex implementation thanks to Martin Froehlich
304 * Revision 1.88 2002/07/15 06:56:59 craigs
305 * Fixed missing brace
307 * Revision 1.87 2002/07/15 06:39:23 craigs
308 * Added function to allow raising of per-process file handle limit
310 * Revision 1.86 2002/06/27 06:38:58 robertj
311 * Changes to remove memory leak display for things that aren't memory leaks.
313 * Revision 1.85 2002/06/27 02:04:01 robertj
314 * Fixed NetBSD compatibility issue, thanks Motoyuki OHMORI.
316 * Revision 1.84 2002/06/04 00:25:31 robertj
317 * Fixed incorrectly initialised trace indent, thanks Artis Kugevics
319 * Revision 1.83 2002/05/21 09:13:00 robertj
320 * Fixed problem when using posix recursive mutexes, thanks Artis Kugevics
322 * Revision 1.82 2002/04/24 01:11:37 robertj
323 * Fixed problem with PTRACE_BLOCK indent level being correct across threads.
325 * Revision 1.81 2002/04/16 10:57:26 rogerh
326 * Change WaitForTermination() so it does not use 100% CPU.
327 * Reported by Andrea <ghittino@tiscali.it>
329 * Revision 1.80 2002/01/23 04:26:36 craigs
330 * Added copy constructors for PSemaphore, PMutex and PSyncPoint to allow
331 * use of default copy constructors for objects containing instances of
332 * these classes
334 * Revision 1.79 2002/01/10 06:36:58 robertj
335 * Fixed possible resource leak under Solaris, thanks Joegen Baclor
337 * Revision 1.78 2001/12/17 11:06:46 robertj
338 * Removed assert on NULL PThread::Current(), can occur if thread from other
339 * subsystem to pwlib
341 * Revision 1.77 2001/10/03 05:11:50 robertj
342 * Fixed PSyncPoint wait with timeout when have pending signals.
344 * Revision 1.76 2001/09/27 23:50:03 craigs
345 * Fixed typo in PSemaphone destructor
347 * Revision 1.75 2001/09/24 10:09:48 rogerh
348 * Fix an uninitialised variable problem.
350 * Revision 1.74 2001/09/20 05:38:25 robertj
351 * Changed PSyncPoint to use pthread cond so timed wait blocks properly.
352 * Also prevented semaphore from being created if subclass does not use it.
354 * Revision 1.73 2001/09/19 17:37:47 craigs
355 * Added support for nested mutexes under Linux
357 * Revision 1.72 2001/09/18 06:53:35 robertj
358 * Made sure suspend can't exit early if get spurious signal
360 * Revision 1.71 2001/09/18 05:56:03 robertj
361 * Fixed numerous problems with thread suspend/resume and signals handling.
363 * Revision 1.70 2001/09/10 03:03:02 robertj
364 * Major change to fix problem with error codes being corrupted in a
365 * PChannel when have simultaneous reads and writes in threads.
366 * Changed threading so does not actually start thread until Resume(), makes
367 * the logic of start up much simpler and more portable.
368 * Quite a bit of tidyin up of the pthreads code.
370 * Revision 1.69 2001/08/30 08:57:40 robertj
371 * Changed calls to usleep to be PThread::Yield(), normalising single
372 * timeslice process swap out.
374 * Revision 1.68 2001/08/20 06:55:45 robertj
375 * Fixed ability to have PMutex::Wait() with times less than one second.
376 * Fixed small error in return value of block on I/O function, not critical.
378 * Revision 1.67 2001/08/07 02:50:03 craigs
379 * Fixed potential race condition in IO blocking
381 * Revision 1.66 2001/07/09 13:23:37 rogerh
382 * Fix a subtle bug in semaphore wait which showed up on FreeBSD
384 * Revision 1.65 2001/05/29 00:49:18 robertj
385 * Added ability to put in a printf %x in thread name to get thread object
386 * address into user settable thread name.
388 * Revision 1.64 2001/05/23 00:18:55 robertj
389 * Added support for real time threads, thanks Erland Lewin.
391 * Revision 1.63 2001/04/20 09:27:25 robertj
392 * Fixed previous change for auto delete threads, must have thread ID zeroed.
394 * Revision 1.62 2001/04/20 09:09:05 craigs
395 * Removed possible race condition whilst shutting down threads
397 * Revision 1.61 2001/03/20 06:44:25 robertj
398 * Lots of changes to fix the problems with terminating threads that are I/O
399 * blocked, especially when doing orderly shutdown of service via SIGTERM.
401 * Revision 1.60 2001/03/14 01:16:11 robertj
402 * Fixed signals processing, now uses housekeeping thread to handle signals
403 * synchronously. This also fixes issues with stopping PServiceProcess.
405 * Revision 1.59 2001/02/25 19:39:42 rogerh
406 * Use a Semaphore on Mac OS X to support threads which are started as 'suspended'
408 * Revision 1.58 2001/02/24 14:49:22 rogerh
409 * Add missing bracket
411 * Revision 1.57 2001/02/24 13:29:34 rogerh
412 * Mac OS X change to avoid Assertion
414 * Revision 1.56 2001/02/24 13:24:24 rogerh
415 * Add PThread support for Mac OS X and Darwin. There is one major issue. This
416 * OS does not suport pthread_kill() and sigwait() so we cannot support the
417 * Suspend() and Resume() functions to start and stop threads and we cannot
418 * create new threads in 'suspended' mode.
419 * Calling Suspend() raises an assertion. Calling Resume() does nothing.
420 * Threads started in 'suspended' mode start immediatly.
422 * Revision 1.55 2001/02/21 22:48:42 robertj
423 * Fixed incorrect test in PSemaphore::WillBlock() just added, thank Artis Kugevics.
425 * Revision 1.54 2001/02/20 00:21:14 robertj
426 * Fixed major bug in PSemapahore::WillBlock(), thanks Tomas Heran.
428 * Revision 1.53 2000/12/21 12:36:32 craigs
429 * Removed potential to stop threads twice
431 * Revision 1.52 2000/12/05 08:24:50 craigs
432 * Fixed problem with EINTR causing havoc
434 * Revision 1.51 2000/11/16 11:06:38 rogerh
435 * Add a better fix for the "user signal 2" aborts seen on FreeBSD 4.2 and above.
436 * We need to sched_yeild() after the pthread_create() to make sure the new thread
437 * actually has a chance to execute. The abort problem was caused when the
438 * resume signal was issued before the thread was ready for it.
440 * Revision 1.50 2000/11/12 23:30:02 craigs
441 * Added extra WaitForTermination to assist bug location
443 * Revision 1.49 2000/11/12 08:16:07 rogerh
444 * This change and the previous change, make pthreads work on FreeBSD 4.2.
445 * FreeBSD has improved its thread signal handling and now correctly generates a
446 * SIGUSR2 signal on a thread (the Resume Signal). However there was no handler
447 * for this signal and applications would abort with "User signal 2".
448 * So, a dummy sigResumeHandler has been added.
450 * Revision 1.48 2000/11/12 07:57:45 rogerh
451 * *** empty log message ***
453 * Revision 1.47 2000/10/31 08:09:51 rogerh
454 * Change return type of PX_GetThreadId() to save unnecessary typecasting
456 * Revision 1.46 2000/10/31 07:52:06 rogerh
457 * Add type casts to allow the code to compile on FreeBSD 4.1.1
459 * Revision 1.45 2000/10/30 05:48:33 robertj
460 * Added assert when get nested mutex.
462 * Revision 1.44 2000/10/24 03:32:40 robertj
463 * Fixed problem where thread that uses PThread::Current() in dtor crashes.
465 * Revision 1.43 2000/10/20 06:11:48 robertj
466 * Added function to change auto delete flag on a thread.
468 * Revision 1.42 2000/09/20 04:24:09 craigs
469 * Added extra tracing, and removed segv on exit when using tracing
471 * Revision 1.41 2000/06/21 01:01:22 robertj
472 * AIX port, thanks Wolfgang Platzer (wolfgang.platzer@infonova.at).
474 * Revision 1.40 2000/04/13 07:21:10 rogerh
475 * Fix typo in #defined
477 * Revision 1.39 2000/04/11 11:38:49 rogerh
478 * More NetBSD Pthread changes
480 * Revision 1.38 2000/04/10 11:47:02 rogerh
481 * Add initial NetBSD pthreads support
483 * Revision 1.37 2000/04/06 12:19:49 rogerh
484 * Add Mac OS X support submitted by Kevin Packard
486 * Revision 1.36 2000/03/20 22:56:34 craigs
487 * Fixed problems with race conditions caused by testing or changing
488 * attributes on a terminated thread. Only occured on a fast machine!
490 * Revision 1.35 2000/03/17 03:45:40 craigs
491 * Fixed problem with connect call hanging
493 * Revision 1.34 2000/03/08 12:17:09 rogerh
494 * Add OpenBSD support
496 * Revision 1.33 2000/02/29 13:18:21 robertj
497 * Added named threads to tracing, thanks to Dave Harvey
499 * Revision 1.32 2000/01/20 08:20:57 robertj
500 * FreeBSD v3 compatibility changes, thanks Roger Hardiman & Motonori Shindo
502 * Revision 1.31 1999/11/18 14:02:57 craigs
503 * Fixed problem with houskeeping thread termination
505 * Revision 1.30 1999/11/15 01:12:56 craigs
506 * Fixed problem with PSemaphore::Wait consuming 100% CPU
508 * Revision 1.29 1999/10/30 13:44:11 craigs
509 * Added correct method of aborting socket operations asynchronously
511 * Revision 1.28 1999/10/24 13:03:30 craigs
512 * Changed to capture io break signal
514 * Revision 1.27 1999/09/23 06:52:16 robertj
515 * Changed PSemaphore to use Posix semaphores.
517 * Revision 1.26 1999/09/03 02:26:25 robertj
518 * Changes to aid in breaking I/O locks on thread termination. Still needs more work esp in BSD!
520 * Revision 1.25 1999/09/02 11:56:35 robertj
521 * Fixed problem with destroying PMutex that is already locked.
523 * Revision 1.24 1999/08/24 13:40:56 craigs
524 * Fixed problem with condwait destorys failing on linux
526 * Revision 1.23 1999/08/23 05:33:45 robertj
527 * Made last threading changes Linux only.
529 * Revision 1.22 1999/08/23 05:14:13 robertj
530 * Removed blocking of interrupt signals as does not work in Linux threads.
532 * Revision 1.21 1999/07/30 00:40:32 robertj
533 * Fixed problem with signal variable in non-Linux platforms
535 * Revision 1.20 1999/07/19 01:32:24 craigs
536 * Changed signals used in pthreads code, is used by linux version.
538 * Revision 1.19 1999/07/15 13:10:55 craigs
539 * Fixed problem with EINTR in nontimed sempahore waits
541 * Revision 1.18 1999/07/15 13:05:33 robertj
542 * Fixed problem with getting EINTR in semaphore wait, is normal, not error.
544 * Revision 1.17 1999/07/11 13:42:13 craigs
545 * pthreads support for Linux
547 * Revision 1.16 1999/05/12 03:29:20 robertj
548 * Fixed problem with semaphore free, done at wrong time.
550 * Revision 1.15 1999/04/29 08:41:26 robertj
551 * Fixed problems with uninitialised mutexes in PProcess.
553 * Revision 1.14 1999/03/16 10:54:16 robertj
554 * Added parameterless version of WaitForTermination.
556 * Revision 1.13 1999/03/16 10:30:37 robertj
557 * Added missing PThread::WaitForTermination function.
559 * Revision 1.12 1999/01/12 12:09:51 robertj
560 * Removed redundent member variable, was in common.
561 * Fixed BSD threads compatibility.
563 * Revision 1.11 1999/01/11 12:05:56 robertj
564 * Fixed some more race conditions in threads.
566 * Revision 1.10 1999/01/11 03:42:26 robertj
567 * Fixed problem with destroying thread automatically.
569 * Revision 1.9 1999/01/09 03:37:28 robertj
570 * Fixed problem with closing thread waiting on semaphore.
571 * Improved efficiency of mutex to use pthread functions directly.
573 * Revision 1.8 1999/01/08 01:31:03 robertj
574 * Support for pthreads under FreeBSD
576 * Revision 1.7 1998/12/15 12:41:07 robertj
577 * Fixed signal handling so can now ^C a pthread version.
579 * Revision 1.6 1998/11/05 09:45:04 robertj
580 * Removed StartImmediate option in thread construction.
582 * Revision 1.5 1998/09/24 04:12:25 robertj
583 * Added open software license.
587 #include <ptlib/socket.h>
588 #include <sched.h> // for sched_yield
589 #include <pthread.h>
590 #include <sys/resource.h>
592 #ifdef P_RTEMS
593 #define SUSPEND_SIG SIGALRM
594 #include <sched.h>
595 #else
596 #define SUSPEND_SIG SIGVTALRM
597 #endif
599 #ifdef P_MACOSX
600 #include <mach/mach.h>
601 #include <mach/thread_policy.h>
602 #include <sys/param.h>
603 #include <sys/sysctl.h>
604 // going to need the main thread for adjusting relative priority
605 static pthread_t baseThread;
606 #endif
608 #ifdef P_HAS_SEMAPHORES_XPG6
609 #include "semaphore.h"
610 #endif
612 int PX_NewHandle(const char *, int);
614 #define PPThreadKill(id, sig) PProcess::Current().PThreadKill(id, sig)
617 #define PAssertPTHREAD(func, args) \
619 unsigned threadOpRetry = 0; \
620 while (PAssertThreadOp(func args, threadOpRetry, #func, __FILE__, __LINE__)); \
623 static BOOL PAssertThreadOp(int retval,
624 unsigned & retry,
625 const char * funcname,
626 const char * file,
627 unsigned line)
629 if (retval == 0) {
630 PTRACE_IF(2, retry > 0, "PWLib\t" << funcname << " required " << retry << " retries!");
631 return FALSE;
634 if (errno == EINTR || errno == EAGAIN) {
635 if (++retry < 1000) {
636 #if defined(P_RTEMS)
637 sched_yield();
638 #else
639 usleep(10000); // Basically just swap out thread to try and clear blockage
640 #endif
641 return TRUE; // Return value to try again
643 // Give up and assert
646 PAssertFunc(file, line, NULL, psprintf("Function %s failed", funcname));
647 return FALSE;
651 PDECLARE_CLASS(PHouseKeepingThread, PThread)
652 public:
653 PHouseKeepingThread()
654 : PThread(1000, NoAutoDeleteThread, NormalPriority, "Housekeeper")
655 { closing = FALSE; Resume(); }
657 void Main();
658 void SetClosing() { closing = TRUE; }
660 protected:
661 BOOL closing;
665 static pthread_mutex_t MutexInitialiser = PTHREAD_MUTEX_INITIALIZER;
668 #define new PNEW
671 void PHouseKeepingThread::Main()
673 PProcess & process = PProcess::Current();
675 while (!closing) {
676 PTimeInterval delay = process.timers.Process();
678 process.breakBlock.Wait(delay);
680 process.PXCheckSignals();
685 void PProcess::SignalTimerChange()
687 if (housekeepingThread == NULL) {
688 #if PMEMORY_CHECK
689 BOOL oldIgnoreAllocations = PMemoryHeap::SetIgnoreAllocations(TRUE);
690 #endif
691 housekeepingThread = new PHouseKeepingThread;
692 #if PMEMORY_CHECK
693 PMemoryHeap::SetIgnoreAllocations(oldIgnoreAllocations);
694 #endif
697 breakBlock.Signal();
701 void PProcess::Construct()
703 #ifndef P_RTEMS
704 // get the file descriptor limit
705 struct rlimit rl;
706 PAssertOS(getrlimit(RLIMIT_NOFILE, &rl) == 0);
707 maxHandles = rl.rlim_cur;
708 PTRACE(4, "PWLib\tMaximum per-process file handles is " << maxHandles);
709 #else
710 maxHandles = 500; // arbitrary value
711 #endif
713 // initialise the housekeeping thread
714 housekeepingThread = NULL;
716 #ifdef P_MACOSX
717 // records the main thread for priority adjusting
718 baseThread = pthread_self();
719 #endif
721 CommonConstruct();
725 BOOL PProcess::SetMaxHandles(int newMax)
727 #ifndef P_RTEMS
728 // get the current process limit
729 struct rlimit rl;
730 PAssertOS(getrlimit(RLIMIT_NOFILE, &rl) == 0);
732 // set the new current limit
733 rl.rlim_cur = newMax;
734 if (setrlimit(RLIMIT_NOFILE, &rl) == 0) {
735 PAssertOS(getrlimit(RLIMIT_NOFILE, &rl) == 0);
736 maxHandles = rl.rlim_cur;
737 if (maxHandles == newMax) {
738 PTRACE(2, "PWLib\tNew maximum per-process file handles set to " << maxHandles);
739 return TRUE;
742 #endif // !P_RTEMS
744 PTRACE(1, "PWLib\tCannot set per-process file handle limit to "
745 << newMax << " (is " << maxHandles << ") - check permissions");
746 return FALSE;
750 PProcess::~PProcess()
752 PreShutdown();
754 // Don't wait for housekeeper to stop if Terminate() is called from it.
755 if (housekeepingThread != NULL && PThread::Current() != housekeepingThread) {
756 housekeepingThread->SetClosing();
757 SignalTimerChange();
758 housekeepingThread->WaitForTermination();
759 delete housekeepingThread;
761 CommonDestruct();
763 PTRACE(5, "PWLib\tDestroyed process " << this);
766 BOOL PProcess::PThreadKill(pthread_t id, unsigned sig)
768 PWaitAndSignal m(threadMutex);
770 if (!activeThreads.Contains((unsigned)id))
771 return FALSE;
773 return pthread_kill(id, sig) == 0;
777 //////////////////////////////////////////////////////////////////////////////
779 PThread::PThread()
781 // see InitialiseProcessThread()
785 void PThread::InitialiseProcessThread()
787 autoDelete = FALSE;
789 PX_origStackSize = 0;
790 PX_threadId = pthread_self();
791 PX_priority = NormalPriority;
792 PX_suspendCount = 0;
794 #ifndef P_HAS_SEMAPHORES
795 PX_waitingSemaphore = NULL;
796 PX_WaitSemMutex = MutexInitialiser;
797 #endif
799 PX_suspendMutex = MutexInitialiser;
801 #ifdef P_RTEMS
802 PAssertOS(socketpair(AF_INET,SOCK_STREAM,0,unblockPipe) == 0);
803 #else
804 PAssertOS(::pipe(unblockPipe) == 0);
805 #endif
807 ((PProcess *)this)->activeThreads.DisallowDeleteObjects();
808 ((PProcess *)this)->activeThreads.SetAt((unsigned)PX_threadId, this);
810 PX_firstTimeStart = FALSE;
812 traceBlockIndentLevel = 0;
816 PThread::PThread(PINDEX stackSize,
817 AutoDeleteFlag deletion,
818 Priority priorityLevel,
819 const PString & name)
820 : threadName(name)
822 autoDelete = (deletion == AutoDeleteThread);
824 PAssert(stackSize > 0, PInvalidParameter);
825 PX_origStackSize = stackSize;
826 PX_threadId = 0;
827 PX_priority = priorityLevel;
828 PX_suspendCount = 1;
830 #ifndef P_HAS_SEMAPHORES
831 PX_waitingSemaphore = NULL;
832 PX_WaitSemMutex = MutexInitialiser;
833 #endif
835 PX_suspendMutex = MutexInitialiser;
837 #ifdef P_RTEMS
838 PAssertOS(socketpair(AF_INET,SOCK_STREAM,0,unblockPipe) == 0);
839 #else
840 PAssertOS(::pipe(unblockPipe) == 0);
841 #endif
842 PX_NewHandle("Thread unblock pipe", PMAX(unblockPipe[0], unblockPipe[1]));
844 // new thread is actually started the first time Resume() is called.
845 PX_firstTimeStart = TRUE;
847 traceBlockIndentLevel = 0;
849 PTRACE(5, "PWLib\tCreated thread " << this << ' ' << threadName);
853 PThread::~PThread()
855 if (PX_threadId != 0 && PX_threadId != pthread_self())
856 Terminate();
858 PAssertPTHREAD(::close, (unblockPipe[0]));
859 PAssertPTHREAD(::close, (unblockPipe[1]));
861 #ifndef P_HAS_SEMAPHORES
862 pthread_mutex_destroy(&PX_WaitSemMutex);
863 #endif
865 // If the mutex was not locked, the unlock will fail */
866 pthread_mutex_trylock(&PX_suspendMutex);
867 pthread_mutex_unlock(&PX_suspendMutex);
868 pthread_mutex_destroy(&PX_suspendMutex);
870 if (this != &PProcess::Current())
871 PTRACE(1, "PWLib\tDestroyed thread " << this << ' ' << threadName << "(id = " << ::hex << PX_threadId << ::dec << ")");
872 else
873 PProcessInstance = NULL;
877 void PThread::Restart()
879 if (!IsTerminated())
880 return;
882 pthread_attr_t threadAttr;
883 pthread_attr_init(&threadAttr);
884 pthread_attr_setdetachstate(&threadAttr, PTHREAD_CREATE_DETACHED);
886 #if defined(P_LINUX)
888 // Set a decent (256K) stack size that won't eat all virtual memory
889 pthread_attr_setstacksize(&threadAttr, 16*PTHREAD_STACK_MIN);
892 Set realtime scheduling if our effective user id is root (only then is this
893 allowed) AND our priority is Highest.
894 As far as I can see, we could use either SCHED_FIFO or SCHED_RR here, it
895 doesn't matter.
896 I don't know if other UNIX OSs have SCHED_FIFO and SCHED_RR as well.
898 WARNING: a misbehaving thread (one that never blocks) started with Highest
899 priority can hang the entire machine. That is why root permission is
900 neccessary.
902 if ((geteuid() == 0) && (PX_priority == HighestPriority))
903 PAssertPTHREAD(pthread_attr_setschedpolicy, (&threadAttr, SCHED_FIFO));
904 #elif defined(P_RTEMS)
905 pthread_attr_setstacksize(&threadAttr, 2*PTHREAD_MINIMUM_STACK_SIZE);
906 pthread_attr_setinheritsched(&threadAttr, PTHREAD_EXPLICIT_SCHED);
907 pthread_attr_setschedpolicy(&threadAttr, SCHED_OTHER);
908 struct sched_param sched_param;
909 sched_param.sched_priority = 125; /* set medium priority */
910 pthread_attr_setschedparam(&threadAttr, &sched_param);
911 #endif
913 PProcess & process = PProcess::Current();
914 PINDEX newHighWaterMark = 0;
915 static PINDEX highWaterMark = 0;
917 // lock the thread list
918 process.threadMutex.Wait();
920 // create the thread
921 PAssertPTHREAD(pthread_create, (&PX_threadId, &threadAttr, PX_ThreadStart, this));
923 // put the thread into the thread list
924 process.activeThreads.SetAt((unsigned)PX_threadId, this);
925 if (process.activeThreads.GetSize() > highWaterMark)
926 newHighWaterMark = highWaterMark = process.activeThreads.GetSize();
928 // unlock the thread list
929 process.threadMutex.Signal();
931 PTRACE_IF(4, newHighWaterMark > 0, "PWLib\tThread high water mark set: " << newHighWaterMark);
933 #ifdef P_MACOSX
934 if (PX_priority == HighestPriority) {
935 PTRACE(1, "set thread to have the highest priority (MACOSX)");
936 SetPriority(HighestPriority);
938 #endif
942 void PX_SuspendSignalHandler(int)
944 PThread * thread = PThread::Current();
945 if (thread == NULL)
946 return;
948 BOOL notResumed = TRUE;
949 while (notResumed) {
950 BYTE ch;
951 notResumed = ::read(thread->unblockPipe[0], &ch, 1) < 0 && errno == EINTR;
952 #if !( defined(P_NETBSD) && defined(P_NO_CANCEL) )
953 pthread_testcancel();
954 #endif
959 void PThread::Suspend(BOOL susp)
961 PAssertPTHREAD(pthread_mutex_lock, (&PX_suspendMutex));
963 // Check for start up condition, first time Resume() is called
964 if (PX_firstTimeStart) {
965 if (susp)
966 PX_suspendCount++;
967 else {
968 if (PX_suspendCount > 0)
969 PX_suspendCount--;
970 if (PX_suspendCount == 0) {
971 PX_firstTimeStart = FALSE;
972 Restart();
976 PAssertPTHREAD(pthread_mutex_unlock, (&PX_suspendMutex));
977 return;
980 #if defined(P_MACOSX) && (P_MACOSX <= 55)
981 // Suspend - warn the user with an Assertion
982 PAssertAlways("Cannot suspend threads on Mac OS X due to lack of pthread_kill()");
983 #else
984 if (PPThreadKill(PX_threadId, 0)) {
986 // if suspending, then see if already suspended
987 if (susp) {
988 PX_suspendCount++;
989 if (PX_suspendCount == 1) {
990 if (PX_threadId != pthread_self()) {
991 signal(SUSPEND_SIG, PX_SuspendSignalHandler);
992 PPThreadKill(PX_threadId, SUSPEND_SIG);
994 else {
995 PAssertPTHREAD(pthread_mutex_unlock, (&PX_suspendMutex));
996 PX_SuspendSignalHandler(SUSPEND_SIG);
997 return; // Mutex already unlocked
1002 // if resuming, then see if to really resume
1003 else if (PX_suspendCount > 0) {
1004 PX_suspendCount--;
1005 if (PX_suspendCount == 0)
1006 PXAbortBlock();
1010 PAssertPTHREAD(pthread_mutex_unlock, (&PX_suspendMutex));
1011 #endif // P_MACOSX
1015 void PThread::Resume()
1017 Suspend(FALSE);
1021 BOOL PThread::IsSuspended() const
1023 if (PX_firstTimeStart)
1024 return TRUE;
1026 if (IsTerminated())
1027 return FALSE;
1029 PAssertPTHREAD(pthread_mutex_lock, ((pthread_mutex_t *)&PX_suspendMutex));
1030 BOOL suspended = PX_suspendCount != 0;
1031 PAssertPTHREAD(pthread_mutex_unlock, ((pthread_mutex_t *)&PX_suspendMutex));
1032 return suspended;
1036 void PThread::SetAutoDelete(AutoDeleteFlag deletion)
1038 PAssert(deletion != AutoDeleteThread || this != &PProcess::Current(), PLogicError);
1039 autoDelete = deletion == AutoDeleteThread;
1042 #ifdef P_MACOSX
1043 // obtain thread priority of the main thread
1044 static unsigned long
1045 GetThreadBasePriority ()
1047 thread_basic_info_data_t threadInfo;
1048 policy_info_data_t thePolicyInfo;
1049 unsigned int count;
1051 if (baseThread == 0) {
1052 return 0;
1055 // get basic info
1056 count = THREAD_BASIC_INFO_COUNT;
1057 thread_info (pthread_mach_thread_np (baseThread), THREAD_BASIC_INFO,
1058 (integer_t*)&threadInfo, &count);
1060 switch (threadInfo.policy) {
1061 case POLICY_TIMESHARE:
1062 count = POLICY_TIMESHARE_INFO_COUNT;
1063 thread_info(pthread_mach_thread_np (baseThread),
1064 THREAD_SCHED_TIMESHARE_INFO,
1065 (integer_t*)&(thePolicyInfo.ts), &count);
1066 return thePolicyInfo.ts.base_priority;
1068 case POLICY_FIFO:
1069 count = POLICY_FIFO_INFO_COUNT;
1070 thread_info(pthread_mach_thread_np (baseThread),
1071 THREAD_SCHED_FIFO_INFO,
1072 (integer_t*)&(thePolicyInfo.fifo), &count);
1073 if (thePolicyInfo.fifo.depressed)
1074 return thePolicyInfo.fifo.depress_priority;
1075 return thePolicyInfo.fifo.base_priority;
1077 case POLICY_RR:
1078 count = POLICY_RR_INFO_COUNT;
1079 thread_info(pthread_mach_thread_np (baseThread),
1080 THREAD_SCHED_RR_INFO,
1081 (integer_t*)&(thePolicyInfo.rr), &count);
1082 if (thePolicyInfo.rr.depressed)
1083 return thePolicyInfo.rr.depress_priority;
1084 return thePolicyInfo.rr.base_priority;
1087 return 0;
1089 #endif
1091 void PThread::SetPriority(Priority priorityLevel)
1093 PX_priority = priorityLevel;
1095 #if defined(P_LINUX)
1096 if (IsTerminated())
1097 return;
1099 struct sched_param sched_param;
1101 if ((priorityLevel == HighestPriority) && (geteuid() == 0) ) {
1102 sched_param.sched_priority = sched_get_priority_min( SCHED_FIFO );
1104 PAssertPTHREAD(pthread_setschedparam, (PX_threadId, SCHED_FIFO, &sched_param));
1106 else if (priorityLevel != HighestPriority) {
1107 /* priority 0 is the only permitted value for the SCHED_OTHER scheduler */
1108 sched_param.sched_priority = 0;
1110 PAssertPTHREAD(pthread_setschedparam, (PX_threadId, SCHED_OTHER, &sched_param));
1112 #endif
1114 #if defined(P_MACOSX)
1115 if (IsTerminated())
1116 return;
1118 if (priorityLevel == HighestPriority) {
1119 /* get fixed priority */
1121 int result;
1123 thread_extended_policy_data_t theFixedPolicy;
1124 thread_precedence_policy_data_t thePrecedencePolicy;
1125 long relativePriority;
1127 theFixedPolicy.timeshare = false; // set to true for a non-fixed thread
1128 result = thread_policy_set (pthread_mach_thread_np(PX_threadId),
1129 THREAD_EXTENDED_POLICY,
1130 (thread_policy_t)&theFixedPolicy,
1131 THREAD_EXTENDED_POLICY_COUNT);
1132 if (result != KERN_SUCCESS) {
1133 PTRACE(1, "thread_policy - Couldn't set thread as fixed priority.");
1136 // set priority
1138 // precedency policy's "importance" value is relative to
1139 // spawning thread's priority
1141 relativePriority = 62 - GetThreadBasePriority();
1142 PTRACE(1, "relativePriority is " << relativePriority << " base priority is " << GetThreadBasePriority());
1144 thePrecedencePolicy.importance = relativePriority;
1145 result = thread_policy_set (pthread_mach_thread_np(PX_threadId),
1146 THREAD_PRECEDENCE_POLICY,
1147 (thread_policy_t)&thePrecedencePolicy,
1148 THREAD_PRECEDENCE_POLICY_COUNT);
1149 if (result != KERN_SUCCESS) {
1150 PTRACE(1, "thread_policy - Couldn't set thread priority.");
1154 #endif
1158 PThread::Priority PThread::GetPriority() const
1160 #if defined(LINUX)
1161 int schedulingPolicy;
1162 struct sched_param schedParams;
1164 PAssertPTHREAD(pthread_getschedparam, (PX_threadId, &schedulingPolicy, &schedParams));
1166 switch( schedulingPolicy )
1168 case SCHED_OTHER:
1169 break;
1171 case SCHED_FIFO:
1172 case SCHED_RR:
1173 return HighestPriority;
1175 default:
1176 /* Unknown scheduler. We don't know what priority this thread has. */
1177 PTRACE(1, "PWLib\tPThread::GetPriority: unknown scheduling policy #" << schedulingPolicy);
1179 #endif
1181 return NormalPriority; /* as good a guess as any */
1185 #ifndef P_HAS_SEMAPHORES
1186 void PThread::PXSetWaitingSemaphore(PSemaphore * sem)
1188 PAssertPTHREAD(pthread_mutex_lock, (&PX_WaitSemMutex));
1189 PX_waitingSemaphore = sem;
1190 PAssertPTHREAD(pthread_mutex_unlock, (&PX_WaitSemMutex));
1192 #endif
1195 #ifdef P_GNU_PTH
1196 // GNU PTH threads version (used by NetBSD)
1197 // Taken from NetBSD pkg patches
1198 void PThread::Sleep(const PTimeInterval & timeout)
1200 PTime lastTime;
1201 PTime targetTime = PTime() + timeout;
1203 sched_yield();
1204 lastTime = PTime();
1206 while (lastTime < targetTime) {
1207 P_timeval tval = targetTime - lastTime;
1208 if (select(0, NULL, NULL, NULL, tval) < 0 && errno != EINTR)
1209 break;
1211 pthread_testcancel();
1213 lastTime = PTime();
1217 #else
1218 // Normal Posix threads version
1219 void PThread::Sleep(const PTimeInterval & timeout)
1221 PTime lastTime;
1222 PTime targetTime = lastTime + timeout;
1223 do {
1224 P_timeval tval = targetTime - lastTime;
1225 if (select(0, NULL, NULL, NULL, tval) < 0 && errno != EINTR)
1226 break;
1228 #if !( defined(P_NETBSD) && defined(P_NO_CANCEL) )
1229 pthread_testcancel();
1230 #endif
1232 lastTime = PTime();
1233 } while (lastTime < targetTime);
1235 #endif
1237 void PThread::Yield()
1239 sched_yield();
1243 PThread * PThread::Current()
1245 PProcess & process = PProcess::Current();
1246 process.threadMutex.Wait();
1247 PThread * thread = process.activeThreads.GetAt((unsigned)pthread_self());
1248 process.threadMutex.Signal();
1249 return thread;
1253 void PThread::Terminate()
1255 if (PX_origStackSize <= 0)
1256 return;
1258 // don't use PThread::Current, as the thread may already not be in the
1259 // active threads list
1260 if (PX_threadId == pthread_self()) {
1261 pthread_exit(0);
1262 return;
1265 if (IsTerminated())
1266 return;
1268 PTRACE(2, "PWLib\tForcing termination of thread " << (void *)this);
1270 PXAbortBlock();
1271 WaitForTermination(20);
1273 #if !defined(P_HAS_SEMAPHORES) && !defined(P_HAS_NAMED_SEMAPHORES)
1274 PAssertPTHREAD(pthread_mutex_lock, (&PX_WaitSemMutex));
1275 if (PX_waitingSemaphore != NULL) {
1276 PAssertPTHREAD(pthread_mutex_lock, (&PX_waitingSemaphore->mutex));
1277 PX_waitingSemaphore->queuedLocks--;
1278 PAssertPTHREAD(pthread_mutex_unlock, (&PX_waitingSemaphore->mutex));
1279 PX_waitingSemaphore = NULL;
1281 PAssertPTHREAD(pthread_mutex_unlock, (&PX_WaitSemMutex));
1282 #endif
1284 #if ( defined(P_NETBSD) && defined(P_NO_CANCEL) )
1285 PPThreadKill(PX_threadId,SIGKILL);
1286 #else
1287 if (PX_threadId) {
1288 pthread_cancel(PX_threadId);
1290 #endif
1294 BOOL PThread::IsTerminated() const
1296 pthread_t id = PX_threadId;
1297 return (id == 0) || !PPThreadKill(id, 0);
1301 void PThread::WaitForTermination() const
1303 if (this == Current()) {
1304 PTRACE(2, "WaitForTermination short circuited");
1305 return;
1308 PXAbortBlock(); // this assist in clean shutdowns on some systems
1310 while (!IsTerminated()) {
1311 Sleep(10); // sleep for 10ms. This slows down the busy loop removing 100%
1312 // CPU usage and also yeilds so other threads can run.
1317 BOOL PThread::WaitForTermination(const PTimeInterval & maxWait) const
1319 if (this == Current()) {
1320 PTRACE(2, "WaitForTermination(t) short circuited");
1321 return TRUE;
1324 PTRACE(6, "PWLib\tWaitForTermination(" << maxWait << ')');
1326 PXAbortBlock(); // this assist in clean shutdowns on some systems
1327 PTimer timeout = maxWait;
1328 while (!IsTerminated()) {
1329 if (timeout == 0)
1330 return FALSE;
1331 Sleep(10); // sleep for 10ms. This slows down the busy loop removing 100%
1332 // CPU usage and also yeilds so other threads can run.
1334 return TRUE;
1338 void * PThread::PX_ThreadStart(void * arg)
1340 PThread * thread = (PThread *)arg;
1341 //don't need to detach the the thread, it was created in the PTHREAD_CREATE_DETACHED state
1342 // Added this to guarantee that the thread creation (PThread::Restart)
1343 // has completed before we start the thread. Then the PX_threadId has
1344 // been set.
1345 pthread_mutex_lock(&thread->PX_suspendMutex);
1346 thread->SetThreadName(thread->GetThreadName());
1347 pthread_mutex_unlock(&thread->PX_suspendMutex);
1349 // make sure the cleanup routine is called when the thread exits
1350 pthread_cleanup_push(&PThread::PX_ThreadEnd, arg);
1352 PTRACE(5, "PWLib\tStarted thread " << thread << ' ' << thread->threadName);
1354 // now call the the thread main routine
1355 thread->Main();
1357 // execute the cleanup routine
1358 pthread_cleanup_pop(1);
1360 return NULL;
1364 void PThread::PX_ThreadEnd(void * arg)
1366 PProcess & process = PProcess::Current();
1367 process.threadMutex.Wait();
1369 PThread * thread = (PThread *)arg;
1370 pthread_t id = thread->GetThreadId();
1371 if (id == 0) {
1372 // Don't know why, but pthreads under Linux at least can call this function
1373 // multiple times! Probably a bug, but we have to allow for it.
1374 process.threadMutex.Signal();
1375 PTRACE(2, "PWLib\tAttempted to multiply end thread " << thread << " ThreadID=" << (void *)id);
1376 return;
1379 // remove this thread from the active thread list
1380 process.activeThreads.SetAt((unsigned)id, NULL);
1382 // delete the thread if required, note this is done this way to avoid
1383 // a race condition, the thread ID cannot be zeroed before the if!
1384 if (thread->autoDelete) {
1385 thread->PX_threadId = 0; // Prevent terminating terminated thread
1386 process.threadMutex.Signal();
1387 PTRACE(5, "PWLib\tEnded thread " << thread << ' ' << thread->threadName);
1389 /* It is now safe to delete this thread. Note that this thread
1390 is deleted after the process.threadMutex.Signal(), which means
1391 PWaitAndSignal(process.threadMutex) could not be used */
1392 delete thread;
1394 else {
1395 thread->PX_threadId = 0;
1396 PString threadName = thread->threadName;
1397 process.threadMutex.Signal();
1398 PTRACE(5, "PWLib\tEnded thread " << thread << ' ' << threadName);
1402 int PThread::PXBlockOnIO(int handle, int type, const PTimeInterval & timeout)
1404 PTRACE(7, "PWLib\tPThread::PXBlockOnIO(" << handle << ',' << type << ')');
1406 if ((handle < 0) || (handle >= PProcess::Current().GetMaxHandles())) {
1407 PTRACE(2, "PWLib\tAttempt to use illegal handle in PThread::PXBlockOnIO, handle=" << handle);
1408 errno = EBADF;
1409 return -1;
1412 // make sure we flush the buffer before doing a write
1413 P_fd_set read_fds;
1414 P_fd_set write_fds;
1415 P_fd_set exception_fds;
1417 int retval;
1418 do {
1419 switch (type) {
1420 case PChannel::PXReadBlock:
1421 case PChannel::PXAcceptBlock:
1422 read_fds = handle;
1423 write_fds.Zero();
1424 exception_fds.Zero();
1425 break;
1426 case PChannel::PXWriteBlock:
1427 read_fds.Zero();
1428 write_fds = handle;
1429 exception_fds.Zero();
1430 break;
1431 case PChannel::PXConnectBlock:
1432 read_fds.Zero();
1433 write_fds = handle;
1434 exception_fds = handle;
1435 break;
1436 default:
1437 PAssertAlways(PLogicError);
1438 return 0;
1441 // include the termination pipe into all blocking I/O functions
1442 read_fds += unblockPipe[0];
1444 P_timeval tval = timeout;
1445 retval = ::select(PMAX(handle, unblockPipe[0])+1,
1446 read_fds, write_fds, exception_fds, tval);
1447 } while (retval < 0 && errno == EINTR);
1449 if ((retval == 1) && read_fds.IsPresent(unblockPipe[0])) {
1450 BYTE ch;
1451 ::read(unblockPipe[0], &ch, 1);
1452 errno = EINTR;
1453 retval = -1;
1454 PTRACE(6, "PWLib\tUnblocked I/O fd=" << unblockPipe[0]);
1457 return retval;
1460 void PThread::PXAbortBlock() const
1462 static BYTE ch = 0;
1463 ::write(unblockPipe[1], &ch, 1);
1464 PTRACE(6, "PWLib\tUnblocking I/O fd=" << unblockPipe[0] << " thread=" << GetThreadName());
1468 ///////////////////////////////////////////////////////////////////////////////
1470 PSemaphore::PSemaphore(PXClass pxc)
1472 pxClass = pxc;
1474 // these should never be used, as this constructor is
1475 // only used for PMutex and PSyncPoint and they have their
1476 // own copy constructors
1478 initialVar = maxCountVar = 0;
1480 if(pxClass == PXSemaphore) {
1481 #if defined(P_HAS_SEMAPHORES)
1482 /* call sem_init, otherwise sem_destroy fails*/
1483 PAssertPTHREAD(sem_init, (&semId, 0, 0));
1484 #elif defined(P_HAS_NAMED_SEMAPHORES)
1485 semId = CreateSem(0);
1486 #else
1487 currentCount = maximumCount = 0;
1488 queuedLocks = 0;
1489 pthread_mutex_init(&mutex, NULL);
1490 pthread_cond_init(&condVar, NULL);
1491 #endif
1496 PSemaphore::PSemaphore(unsigned initial, unsigned maxCount)
1498 pxClass = PXSemaphore;
1500 initialVar = initial;
1501 maxCountVar = maxCount;
1503 #if defined(P_HAS_SEMAPHORES)
1504 PAssertPTHREAD(sem_init, (&semId, 0, initial));
1505 #elif defined(P_HAS_NAMED_SEMAPHORES)
1506 semId = CreateSem(initialVar);
1507 #else
1508 PAssertPTHREAD(pthread_mutex_init, (&mutex, NULL));
1509 PAssertPTHREAD(pthread_cond_init, (&condVar, NULL));
1511 PAssert(maxCount > 0, "Invalid semaphore maximum.");
1512 if (initial > maxCount)
1513 initial = maxCount;
1515 currentCount = initial;
1516 maximumCount = maxCount;
1517 queuedLocks = 0;
1518 #endif
1522 PSemaphore::PSemaphore(const PSemaphore & sem)
1524 pxClass = sem.GetSemClass();
1526 initialVar = sem.GetInitial();
1527 maxCountVar = sem.GetMaxCount();
1529 if(pxClass == PXSemaphore) {
1530 #if defined(P_HAS_SEMAPHORES)
1531 PAssertPTHREAD(sem_init, (&semId, 0, initialVar));
1532 #elif defined(P_HAS_NAMED_SEMAPHORES)
1533 semId = CreateSem(initialVar);
1534 #else
1535 PAssertPTHREAD(pthread_mutex_init, (&mutex, NULL));
1536 PAssertPTHREAD(pthread_cond_init, (&condVar, NULL));
1538 PAssert(maxCountVar > 0, "Invalid semaphore maximum.");
1539 if (initialVar > maxCountVar)
1540 initialVar = maxCountVar;
1542 currentCount = initialVar;
1543 maximumCount = maxCountVar;
1544 queuedLocks = 0;
1545 #endif
1549 PSemaphore::~PSemaphore()
1551 if(pxClass == PXSemaphore) {
1552 #if defined(P_HAS_SEMAPHORES)
1553 PAssertPTHREAD(sem_destroy, (&semId));
1554 #elif defined(P_HAS_NAMED_SEMAPHORES)
1555 PAssertPTHREAD(sem_close, (semId));
1556 #else
1557 PAssert(queuedLocks == 0, "Semaphore destroyed with queued locks");
1558 PAssertPTHREAD(pthread_mutex_destroy, (&mutex));
1559 PAssertPTHREAD(pthread_cond_destroy, (&condVar));
1560 #endif
1564 #if defined(P_HAS_NAMED_SEMAPHORES)
1565 sem_t * PSemaphore::CreateSem(unsigned initialValue)
1567 sem_t *sem;
1569 // Since sem_open and sem_unlink are two operations, there is a small
1570 // window of opportunity that two simultaneous accesses may return
1571 // the same semaphore. Therefore, the static mutex is used to
1572 // prevent this, even if the chances are small
1573 static pthread_mutex_t semCreationMutex = PTHREAD_MUTEX_INITIALIZER;
1574 PAssertPTHREAD(pthread_mutex_lock, (&semCreationMutex));
1576 sem_unlink("/pwlib_sem");
1577 sem = sem_open("/pwlib_sem", (O_CREAT | O_EXCL), 700, initialValue);
1579 PAssertPTHREAD(pthread_mutex_unlock, (&semCreationMutex));
1581 PAssert(((int)sem != SEM_FAILED), "Couldn't create named semaphore");
1582 return sem;
1584 #endif
1586 void PSemaphore::Wait()
1588 #if defined(P_HAS_SEMAPHORES)
1589 PAssertPTHREAD(sem_wait, (&semId));
1590 #elif defined(P_HAS_NAMED_SEMAPHORES)
1591 PAssertPTHREAD(sem_wait, (semId));
1592 #else
1593 PAssertPTHREAD(pthread_mutex_lock, (&mutex));
1595 queuedLocks++;
1596 PThread::Current()->PXSetWaitingSemaphore(this);
1598 while (currentCount == 0) {
1599 int err = pthread_cond_wait(&condVar, &mutex);
1600 PAssert(err == 0 || err == EINTR, psprintf("wait error = %i", err));
1603 PThread::Current()->PXSetWaitingSemaphore(NULL);
1604 queuedLocks--;
1606 currentCount--;
1608 PAssertPTHREAD(pthread_mutex_unlock, (&mutex));
1609 #endif
1613 BOOL PSemaphore::Wait(const PTimeInterval & waitTime)
1615 if (waitTime == PMaxTimeInterval) {
1616 Wait();
1617 return TRUE;
1620 // create absolute finish time
1621 PTime finishTime;
1622 finishTime += waitTime;
1624 #if defined(P_HAS_SEMAPHORES)
1625 #ifdef P_HAS_SEMAPHORES_XPG6
1626 // use proper timed spinlocks if supported.
1627 // http://www.opengroup.org/onlinepubs/007904975/functions/sem_timedwait.html
1629 struct timespec absTime;
1630 absTime.tv_sec = finishTime.GetTimeInSeconds();
1631 absTime.tv_nsec = finishTime.GetMicrosecond() * 1000;
1633 if (sem_timedwait(&semId, &absTime) == 0) {
1634 return TRUE;
1636 else {
1637 return FALSE;
1640 #else
1641 // loop until timeout, or semaphore becomes available
1642 // don't use a PTimer, as this causes the housekeeping
1643 // thread to get very busy
1644 do {
1645 if (sem_trywait(&semId) == 0)
1646 return TRUE;
1648 #if defined(P_LINUX)
1649 // sched_yield in a tight loop is bad karma
1650 // for the linux scheduler: http://www.ussg.iu.edu/hypermail/linux/kernel/0312.2/1127.html
1651 PThread::Current()->Sleep(10);
1652 #else
1653 PThread::Yield();
1654 #endif
1655 } while (PTime() < finishTime);
1657 return FALSE;
1659 #endif
1660 #elif defined(P_HAS_NAMED_SEMAPHORES)
1661 do {
1662 if(sem_trywait(semId) == 0)
1663 return TRUE;
1664 PThread::Current()->Sleep(10);
1665 } while (PTime() < finishTime);
1667 return FALSE;
1668 #else
1670 struct timespec absTime;
1671 absTime.tv_sec = finishTime.GetTimeInSeconds();
1672 absTime.tv_nsec = finishTime.GetMicrosecond() * 1000;
1674 PAssertPTHREAD(pthread_mutex_lock, (&mutex));
1676 PThread * thread = PThread::Current();
1677 thread->PXSetWaitingSemaphore(this);
1678 queuedLocks++;
1680 BOOL ok = TRUE;
1681 while (currentCount == 0) {
1682 int err = pthread_cond_timedwait(&condVar, &mutex, &absTime);
1683 if (err == ETIMEDOUT) {
1684 ok = FALSE;
1685 break;
1687 else
1688 PAssert(err == 0 || err == EINTR, psprintf("timed wait error = %i", err));
1691 thread->PXSetWaitingSemaphore(NULL);
1692 queuedLocks--;
1694 if (ok)
1695 currentCount--;
1697 PAssertPTHREAD(pthread_mutex_unlock, ((pthread_mutex_t *)&mutex));
1699 return ok;
1700 #endif
1704 void PSemaphore::Signal()
1706 #if defined(P_HAS_SEMAPHORES)
1707 PAssertPTHREAD(sem_post, (&semId));
1708 #elif defined(P_HAS_NAMED_SEMAPHORES)
1709 PAssertPTHREAD(sem_post, (semId));
1710 #else
1711 PAssertPTHREAD(pthread_mutex_lock, (&mutex));
1713 if (currentCount < maximumCount)
1714 currentCount++;
1716 if (queuedLocks > 0)
1717 PAssertPTHREAD(pthread_cond_signal, (&condVar));
1719 PAssertPTHREAD(pthread_mutex_unlock, (&mutex));
1720 #endif
1724 BOOL PSemaphore::WillBlock() const
1726 #if defined(P_HAS_SEMAPHORES)
1727 if (sem_trywait((sem_t *)&semId) != 0) {
1728 PAssertOS(errno == EAGAIN || errno == EINTR);
1729 return TRUE;
1731 PAssertPTHREAD(sem_post, ((sem_t *)&semId));
1732 return FALSE;
1733 #elif defined(P_HAS_NAMED_SEMAPHORES)
1734 if (sem_trywait(semId) != 0) {
1735 PAssertOS(errno == EAGAIN || errno == EINTR);
1736 return TRUE;
1738 PAssertPTHREAD(sem_post, (semId));
1739 return FALSE;
1740 #else
1741 return currentCount == 0;
1742 #endif
1745 #if defined(P_QNX) && (P_HAS_RECURSIVE_MUTEX == 1)
1746 #define PTHREAD_MUTEX_RECURSIVE_NP PTHREAD_MUTEX_RECURSIVE
1747 #endif
1748 #if defined(P_MACOSX) && (P_HAS_RECURSIVE_MUTEX == 1)
1749 #define PTHREAD_MUTEX_RECURSIVE_NP PTHREAD_MUTEX_RECURSIVE
1750 #endif
1752 PTimedMutex::PTimedMutex()
1753 // : PSemaphore(PXMutex)
1755 #if P_HAS_RECURSIVE_MUTEX
1756 pthread_mutexattr_t attr;
1757 PAssertPTHREAD(pthread_mutexattr_init, (&attr));
1758 PAssertPTHREAD(pthread_mutexattr_settype, (&attr, PTHREAD_MUTEX_RECURSIVE_NP));
1759 PAssertPTHREAD(pthread_mutex_init, (&mutex, &attr));
1760 PAssertPTHREAD(pthread_mutexattr_destroy, (&attr));
1761 #else
1762 PAssertPTHREAD(pthread_mutex_init, (&mutex, NULL));
1763 #endif
1766 PTimedMutex::PTimedMutex(const PTimedMutex & /*mut*/)
1767 // : PSemaphore(PXMutex)
1769 #if P_HAS_RECURSIVE_MUTEX
1770 pthread_mutexattr_t attr;
1771 PAssertPTHREAD(pthread_mutexattr_init, (&attr));
1772 PAssertPTHREAD(pthread_mutexattr_settype, (&attr, PTHREAD_MUTEX_RECURSIVE_NP));
1773 PAssertPTHREAD(pthread_mutex_init, (&mutex, &attr));
1774 PAssertPTHREAD(pthread_mutexattr_destroy, (&attr));
1775 #else
1776 pthread_mutex_init(&mutex, NULL);
1777 #endif
1780 PTimedMutex::~PTimedMutex()
1782 int result = pthread_mutex_destroy(&mutex);
1783 PINDEX i = 0;
1784 while ((result == EBUSY) && (i++ < 20)) {
1785 pthread_mutex_unlock(&mutex);
1786 result = pthread_mutex_destroy(&mutex);
1788 #ifdef _DEBUG
1789 PAssert((result == 0), "Error destroying mutex");
1790 #endif
1793 void PTimedMutex::Wait()
1795 pthread_t currentThreadId = pthread_self();
1797 #if P_HAS_RECURSIVE_MUTEX == 0
1799 // if the mutex is already acquired by this thread,
1800 // then just increment the lock count
1801 if (pthread_equal(lockerId, currentThreadId)) {
1802 // Note this does not need a lock as it can only be touched by the thread
1803 // which already has the mutex locked.
1804 ++lockCount;
1805 return;
1807 #endif
1809 // acquire the lock for real
1810 PAssertPTHREAD(pthread_mutex_lock, (&mutex));
1812 #if P_HAS_RECURSIVE_MUTEX == 0
1813 PAssert((lockerId == (pthread_t)-1) && (lockCount.IsZero()),
1814 "PMutex acquired whilst locked by another thread");
1815 // Note this is protected by the mutex itself only the thread with
1816 // the lock can alter it.
1817 #endif
1819 lockerId = currentThreadId;
1823 BOOL PTimedMutex::Wait(const PTimeInterval & waitTime)
1825 // get the current thread ID
1826 pthread_t currentThreadId = pthread_self();
1828 // if waiting indefinitely, then do so
1829 if (waitTime == PMaxTimeInterval) {
1830 Wait();
1831 lockerId = currentThreadId;
1832 return TRUE;
1835 #if P_HAS_RECURSIVE_MUTEX == 0
1836 // if we already have the mutex, return immediately
1837 if (pthread_equal(lockerId, currentThreadId)) {
1838 // Note this does not need a lock as it can only be touched by the thread
1839 // which already has the mutex locked.
1840 ++lockCount;
1841 return TRUE;
1843 #endif
1845 // create absolute finish time
1846 PTime finishTime;
1847 finishTime += waitTime;
1849 #if P_PTHREADS_XPG6
1851 struct timespec absTime;
1852 absTime.tv_sec = finishTime.GetTimeInSeconds();
1853 absTime.tv_nsec = finishTime.GetMicrosecond() * 1000;
1855 if (pthread_mutex_timedlock(&mutex, &absTime) != 0)
1856 return FALSE;
1858 #if P_HAS_RECURSIVE_MUTEX == 0
1859 PAssert((lockerId == (pthread_t)-1) && (lockCount.IsZero()),
1860 "PMutex acquired whilst locked by another thread");
1861 #endif
1863 // Note this is protected by the mutex itself only the thread with
1864 // the lock can alter it.
1865 lockerId = currentThreadId;
1866 return TRUE;
1868 #else // P_PTHREADS_XPG6
1870 do {
1871 if (pthread_mutex_trylock(&mutex) == 0) {
1872 #if P_HAS_RECURSIVE_MUTEX == 0
1873 PAssert((lockerId == (pthread_t)-1) && (lockCount.IsZero()),
1874 "PMutex acquired whilst locked by another thread");
1875 #endif
1876 lockerId = currentThreadId;
1878 return TRUE;
1881 PThread::Current()->Sleep(10); // sleep for 10ms
1882 } while (PTime() < finishTime);
1884 return FALSE;
1886 #endif // P_PTHREADS_XPG6
1890 void PTimedMutex::Signal()
1892 #if P_HAS_RECURSIVE_MUTEX == 0
1893 if (!pthread_equal(lockerId, pthread_self())) {
1894 PAssertAlways("PMutex signal failed - no matching wait or signal by wrong thread");
1895 return;
1898 // if lock was recursively acquired, then decrement the counter
1899 // Note this does not need a separate lock as it can only be touched by the thread
1900 // which already has the mutex locked.
1901 if (!lockCount.IsZero()) {
1902 --lockCount;
1903 return;
1906 // otherwise mark mutex as available
1907 lockerId = (pthread_t)-1;
1909 #endif
1911 PAssertPTHREAD(pthread_mutex_unlock, (&mutex));
1915 BOOL PTimedMutex::WillBlock() const
1917 #if P_HAS_RECURSIVE_MUTEX == 0
1918 pthread_t currentThreadId = pthread_self();
1919 if (currentThreadId == lockerId)
1920 return FALSE;
1921 #endif
1923 pthread_mutex_t * mp = (pthread_mutex_t*)&mutex;
1924 if (pthread_mutex_trylock(mp) != 0)
1925 return TRUE;
1927 PAssertPTHREAD(pthread_mutex_unlock, (mp));
1928 return FALSE;
1932 PSyncPoint::PSyncPoint()
1933 : PSemaphore(PXSyncPoint)
1935 PAssertPTHREAD(pthread_mutex_init, (&mutex, NULL));
1936 PAssertPTHREAD(pthread_cond_init, (&condVar, NULL));
1937 signalCount = 0;
1940 PSyncPoint::PSyncPoint(const PSyncPoint &)
1941 : PSemaphore(PXSyncPoint)
1943 PAssertPTHREAD(pthread_mutex_init, (&mutex, NULL));
1944 PAssertPTHREAD(pthread_cond_init, (&condVar, NULL));
1945 signalCount = 0;
1948 PSyncPoint::~PSyncPoint()
1950 PAssertPTHREAD(pthread_mutex_destroy, (&mutex));
1951 PAssertPTHREAD(pthread_cond_destroy, (&condVar));
1954 void PSyncPoint::Wait()
1956 PAssertPTHREAD(pthread_mutex_lock, (&mutex));
1957 while (signalCount == 0)
1958 pthread_cond_wait(&condVar, &mutex);
1959 signalCount--;
1960 PAssertPTHREAD(pthread_mutex_unlock, (&mutex));
1964 BOOL PSyncPoint::Wait(const PTimeInterval & waitTime)
1966 PAssertPTHREAD(pthread_mutex_lock, (&mutex));
1968 PTime finishTime;
1969 finishTime += waitTime;
1970 struct timespec absTime;
1971 absTime.tv_sec = finishTime.GetTimeInSeconds();
1972 absTime.tv_nsec = finishTime.GetMicrosecond() * 1000;
1974 int err = 0;
1975 while (signalCount == 0) {
1976 err = pthread_cond_timedwait(&condVar, &mutex, &absTime);
1977 if (err == 0 || err == ETIMEDOUT)
1978 break;
1980 PAssertOS(err == EINTR && errno == EINTR);
1983 if (err == 0)
1984 signalCount--;
1986 PAssertPTHREAD(pthread_mutex_unlock, (&mutex));
1988 return err == 0;
1992 void PSyncPoint::Signal()
1994 PAssertPTHREAD(pthread_mutex_lock, (&mutex));
1995 signalCount++;
1996 PAssertPTHREAD(pthread_cond_signal, (&condVar));
1997 PAssertPTHREAD(pthread_mutex_unlock, (&mutex));
2001 BOOL PSyncPoint::WillBlock() const
2003 return signalCount == 0;