Fixed DevStudio 2003 build with memory check code.
[pwlib.git] / src / ptlib / unix / tlibthrd.cxx
blob6acd8df5d4dc816e66ae60ff65d4fc11ebcb6a2f
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.175 2007/09/05 12:47:08 csoutheren
31 * Fixes, fixes, fixes
33 * Revision 1.174 2007/09/05 12:40:11 csoutheren
34 * Add generic test for mutex type
36 * Revision 1.173 2007/09/05 11:58:47 csoutheren
37 * Fixed build on MacOSX
39 * Revision 1.170 2007/08/17 07:29:21 csoutheren
40 * Fix build on MacOSX
42 * Revision 1.169 2007/08/17 07:05:13 csoutheren
43 * Fix problem with false asserts based on mutex locking
45 * Revision 1.168 2007/08/17 05:29:19 csoutheren
46 * Add field to Linux showing locking thread to assist in debugging
48 * Revision 1.167 2007/07/19 08:11:47 csoutheren
49 * Fix problem with hex in log stream
51 * Revision 1.166 2007/07/06 02:12:14 csoutheren
52 * Add extra memory leak debugging on Linux
53 * Remove compile warnings
55 * Revision 1.165 2007/05/01 10:20:44 csoutheren
56 * Applied 1703617 - Prevention of application deadlock caused by too many timers
57 * Thanks to Fabrizio Ammollo
59 * Revision 1.164 2006/10/23 01:15:16 csoutheren
60 * Revert to revision 1.153 to fix crash problem with SIP connections
62 * Revision 1.153 2006/06/25 21:46:38 dereksmithies
63 * Thanks to Paul Nader for this fix which fixes thread cleanup
64 * issues on SMP machines. Good find.
66 * Revision 1.152 2006/03/01 08:29:33 csoutheren
67 * Applied patch #1439578 PTrace / PThread::PX_ThreadEnd deadlock fix
68 * Thanks to Hannes Friederich
70 * Revision 1.151 2006/01/29 22:35:47 csoutheren
71 * Added fix for thread termination problems on SMP machines
72 * Thanks to Derek Smithies
74 * Revision 1.150 2005/12/05 22:35:24 csoutheren
75 * Only assert in PTimedMutex destructor if _DEBUG is enabled
77 * Revision 1.149 2005/12/04 22:07:26 csoutheren
78 * Fixed uninitialised variable
80 * Revision 1.148 2005/12/01 00:55:19 csoutheren
81 * Removed chance of endless loop in PTimedMutex destructor
83 * Revision 1.147 2005/11/25 00:06:12 csoutheren
84 * Applied patch #1364593 from Hannes Friederich
85 * Also changed so PTimesMutex is no longer descended from PSemaphore on
86 * non-Windows platforms
88 * Revision 1.146 2005/11/22 22:38:36 dsandras
89 * Removed Assert that was causing problem if the mutex is locked when being
90 * destroyed.
92 * Revision 1.145 2005/11/18 22:26:07 dsandras
93 * Removed a few more CONST's to match with previous commit and fix permanent
94 * deadlock.
96 * Revision 1.144 2005/11/14 22:41:53 csoutheren
97 * Reverted Wait and Signal to non-const - there is no way we can guarantee that all
98 * descendant classes everywhere will be changed over, so we have to keep the
99 * original API
101 * Revision 1.143 2005/11/04 09:44:30 csoutheren
102 * Applied patch #1324589
103 * Removed race conditions in PSemaphore and thread handling
104 * Thanks to Frederic Heem
106 * Revision 1.142 2005/11/04 06:56:10 csoutheren
107 * Added new class PSync as abstract base class for all mutex/sempahore classes
108 * Changed PCriticalSection to use Wait/Signal rather than Enter/Leave
109 * Changed Wait/Signal to be const member functions
110 * Renamed PMutex to PTimedMutex and made PMutex synonym for PCriticalSection.
111 * This allows use of very efficient mutex primitives in 99% of cases where timed waits
112 * are not needed
114 * Revision 1.141 2005/07/22 04:19:18 csoutheren
115 * Removed redundant check of thread ID introduced in last patch
116 * Removed race condition in thread shutdown found by Derek Smithies
118 * Revision 1.140 2005/07/21 13:04:11 csoutheren
119 * Removed race condition where activeThreads list does not contain
120 * thread until some time after thread is started. Fixed by moving
121 * list insertion to immediately after pthread_create, and using lock
123 * Revision 1.139 2005/07/21 00:09:08 csoutheren
124 * Added workaround for braindead behaviour of pthread_kill
125 * Thanks to "martin martin" <acevedoma@hotmail.com>
127 * Revision 1.138 2005/05/03 11:58:46 csoutheren
128 * Fixed various problems reported by valgrind
129 * Thanks to Paul Cadach
131 * Revision 1.137 2005/01/21 21:25:19 csoutheren
132 * Removed incorrect return in PThread::WaitForTermination
134 * Revision 1.136 2005/01/16 23:00:37 csoutheren
135 * Fixed problem when calling WaitForTermination from within the same thread
137 * Revision 1.135 2004/12/21 06:30:55 csoutheren
138 * Added explicit stack size for pthreads to minimise VM usage, thanks to Diana Cionoiu
140 * Revision 1.134 2004/09/02 07:55:44 csoutheren
141 * Added extra PXAbortBlock to WaitForTermination to assist in terminaing
142 * threads under certain conditions
144 * Revision 1.133 2004/06/24 11:29:44 csoutheren
145 * Changed to use pthread_mutex_timedlock for more efficient mutex wait operations
146 * Thanks to Michal Zygmuntowicz
148 * Revision 1.132 2004/06/01 07:42:20 csoutheren
149 * Restored memory allocation checking
150 * Added configure flag to enable, thanks to Derek Smithies
152 * Revision 1.131 2004/05/21 00:49:16 csoutheren
153 * Added PreShutdown to ~PProcess
155 * Revision 1.130 2004/04/27 04:36:47 rjongbloed
156 * Fixed occassional crash on exit due to level 5 trace in PProcess
157 * destructor that needs an undestructed PProcess.
158 * Added some more logging for unblocking threads.
160 * Revision 1.129 2004/04/12 03:35:27 csoutheren
161 * Fixed problems with non-recursuve mutexes and critical sections on
162 * older compilers and libc
164 * Revision 1.128 2004/04/12 00:58:45 csoutheren
165 * Fixed PAtomicInteger on Linux, and modified PMutex to use it
167 * Revision 1.127 2004/04/11 07:58:08 csoutheren
168 * Added configure.in check for recursive mutexes, and changed implementation
169 * without recursive mutexes to use PCriticalSection or atomic word structs
171 * Revision 1.126 2004/03/24 02:37:04 csoutheren
172 * Fixed problem with incorrect usage of sem_timedwait
174 * Revision 1.125 2004/03/23 04:56:23 csoutheren
175 * Added patches to use XPG6 threading under Linux if available
176 * Thanks to Matthew Hodgson
178 * Revision 1.124 2004/02/01 11:23:16 dsandras
179 * Reverted previous Change and removed Yield call from Current (). Fix from Christian Meder <chris@onestepahead.de>. Thanks for your help, Christian!
181 * Revision 1.123 2004/01/31 13:49:18 dominance
182 * Added 2.6 performance fix as proposed by Christian Meder <chris@onestepahead.de>.
184 * Revision 1.122 2003/09/17 09:02:15 csoutheren
185 * Removed memory leak detection code
187 * Revision 1.121 2003/05/16 17:40:55 shawn
188 * On Mac OS X, thread with the highest priority should use fixed priority
189 * scheduling policy. This avoids starvation caused by desktop activity.
191 * Revision 1.120 2003/05/02 00:58:40 dereks
192 * Add test for linux at the end of PMutex::Signal. Thanks Robert!
194 * Revision 1.119 2003/05/02 00:39:11 dereks
195 * Changes to make threading work on Redhat 9
197 * Revision 1.118 2003/04/24 12:03:13 rogerh
198 * Calling pthread_mutex_unlock() on a mutex which is not locked can be
199 * considered an error. NetBSD now enforce this error so we need to quickly
200 * try locking the mutex before unlocking it in ~PThread and ~PSemaphore.
202 * Revision 1.117 2003/04/08 03:29:31 robertj
203 * Fixed IsSuspeneded() so returns TRUE if thread not started yet, this makes
204 * it the same as the Win32 semantics.
206 * Revision 1.116 2003/03/10 15:37:00 rogerh
207 * fix IsTerminated() function.
209 * Revision 1.115 2003/03/07 00:07:15 robertj
210 * Fixed Mac OS X patch which broke every other platform.
212 * Revision 1.114 2003/03/06 08:58:48 rogerh
213 * P_MACOSX now carries the OSRELEASE. Use this to enable better threads
214 * support on Darwin 6.4. Submitted by Shawn.
216 * Revision 1.113 2003/02/20 23:32:00 robertj
217 * More RTEMS support patches, thanks Sebastian Meyer.
219 * Revision 1.112 2003/01/24 10:21:06 robertj
220 * Fixed issues in RTEMS support, thanks Vladimir Nesic
222 * Revision 1.111 2003/01/20 10:13:18 rogerh
223 * NetBSD thread changes
225 * Revision 1.110 2003/01/20 10:05:46 rogerh
226 * NetBSD thread changes
228 * Revision 1.109 2003/01/08 08:47:51 rogerh
229 * Add new Sleep() function for GNU PTH threads.
230 * Taken from NetBSD's package which uses PTH.
231 * Note: I am not sure this works correctly.
233 * Revision 1.108 2003/01/06 18:49:15 rogerh
234 * Back out pthead_kill to pthread_cancel change on NetBSD
236 * Revision 1.107 2002/12/11 05:39:26 robertj
237 * Added logging for file handle changes.
238 * Fixd bug where internal maxHandles not set when increased.
240 * Revision 1.106 2002/12/02 03:57:18 robertj
241 * More RTEMS support patches, thank you Vladimir Nesic.
243 * Revision 1.105 2002/11/22 10:14:07 robertj
244 * QNX port, thanks Xiaodan Tang
246 * Revision 1.104 2002/11/04 16:01:27 rogerh
247 * Using pthread_cancel and not pthread_kill with SIGKILL to terminate a thread
248 * On FreeBSD the thread does not have a handler for SIGKILL, it passes it up
249 * to the main process which gets killed! Assume the other BSDs are the same.
251 * Revision 1.103 2002/10/24 00:40:56 robertj
252 * Put back ability to terminate a thread from that threads context (removed
253 * in revision 1.101) but requires that destructor not do so.
254 * Changed pipe close to allow for possible EINTR, and retry close.
256 * Revision 1.102 2002/10/24 00:25:13 robertj
257 * Changed high load thread problem fix from the termination function to start
258 * function to finally, once and for all (I hope!) fix the race condition.
260 * Revision 1.101 2002/10/23 14:56:22 craigs
261 * Fixed problem with pipe leak under some circumstances
263 * Revision 1.100 2002/10/23 04:29:32 robertj
264 * Improved debugging for thread create/start/stop/destroy.
265 * Fixed race condition bug if auto-delete thread starts and completes before
266 * pthread_create returns, PX_threadId is not set yet!
268 * Revision 1.99 2002/10/22 07:42:52 robertj
269 * Added extra debugging for file handle and thread leak detection.
271 * Revision 1.98 2002/10/18 03:05:39 robertj
272 * Fixed thread leak caused by fixing the thread crash a few revisions back,
273 * caused by strange pthreads behaviour, at least under Linux.
275 * Revision 1.97 2002/10/17 13:44:27 robertj
276 * Port to RTEMS, thanks Vladimir Nesic.
278 * Revision 1.96 2002/10/17 12:57:24 robertj
279 * Added ability to increase maximum file handles on a process.
281 * Revision 1.95 2002/10/16 11:26:29 rogerh
282 * Add missing include. Noticed by Matthias on the GnomeMeeting IRC
284 * Revision 1.94 2002/10/10 03:09:48 robertj
285 * Fixed high load race condition when starting threads.
287 * Revision 1.93 2002/10/05 05:22:43 robertj
288 * Fixed adding GetThreadId() function.
290 * Revision 1.92 2002/10/01 06:27:48 robertj
291 * Added bullet proofing against possible EINTR error returns on all pthread
292 * functions when under heavy load. Linux really should NOT do this, but ...
294 * Revision 1.91 2002/09/04 03:14:18 robertj
295 * Backed out changes submitted by Martin Froehlich as they do not appear to
296 * actually do anything other than add a sychronisation point. The variables
297 * the patches intended to protect were already protected.
298 * Fixed bug where if a PMutex was signalled by a thread that did not have it
299 * locked, it would assert but continue to alter PMutex variables such that
300 * a deadlock or crash is likely.
302 * Revision 1.90 2002/08/29 01:50:40 robertj
303 * Changed the pthread_create so does retries if get EINTR or EAGAIN errors
304 * which indicate a (possibly) temporary resource limit.
305 * Enabled and adjusted tracing.
307 * Revision 1.89 2002/08/22 13:05:57 craigs
308 * Fixed problems with mutex implementation thanks to Martin Froehlich
310 * Revision 1.88 2002/07/15 06:56:59 craigs
311 * Fixed missing brace
313 * Revision 1.87 2002/07/15 06:39:23 craigs
314 * Added function to allow raising of per-process file handle limit
316 * Revision 1.86 2002/06/27 06:38:58 robertj
317 * Changes to remove memory leak display for things that aren't memory leaks.
319 * Revision 1.85 2002/06/27 02:04:01 robertj
320 * Fixed NetBSD compatibility issue, thanks Motoyuki OHMORI.
322 * Revision 1.84 2002/06/04 00:25:31 robertj
323 * Fixed incorrectly initialised trace indent, thanks Artis Kugevics
325 * Revision 1.83 2002/05/21 09:13:00 robertj
326 * Fixed problem when using posix recursive mutexes, thanks Artis Kugevics
328 * Revision 1.82 2002/04/24 01:11:37 robertj
329 * Fixed problem with PTRACE_BLOCK indent level being correct across threads.
331 * Revision 1.81 2002/04/16 10:57:26 rogerh
332 * Change WaitForTermination() so it does not use 100% CPU.
333 * Reported by Andrea <ghittino@tiscali.it>
335 * Revision 1.80 2002/01/23 04:26:36 craigs
336 * Added copy constructors for PSemaphore, PMutex and PSyncPoint to allow
337 * use of default copy constructors for objects containing instances of
338 * these classes
340 * Revision 1.79 2002/01/10 06:36:58 robertj
341 * Fixed possible resource leak under Solaris, thanks Joegen Baclor
343 * Revision 1.78 2001/12/17 11:06:46 robertj
344 * Removed assert on NULL PThread::Current(), can occur if thread from other
345 * subsystem to pwlib
347 * Revision 1.77 2001/10/03 05:11:50 robertj
348 * Fixed PSyncPoint wait with timeout when have pending signals.
350 * Revision 1.76 2001/09/27 23:50:03 craigs
351 * Fixed typo in PSemaphone destructor
353 * Revision 1.75 2001/09/24 10:09:48 rogerh
354 * Fix an uninitialised variable problem.
356 * Revision 1.74 2001/09/20 05:38:25 robertj
357 * Changed PSyncPoint to use pthread cond so timed wait blocks properly.
358 * Also prevented semaphore from being created if subclass does not use it.
360 * Revision 1.73 2001/09/19 17:37:47 craigs
361 * Added support for nested mutexes under Linux
363 * Revision 1.72 2001/09/18 06:53:35 robertj
364 * Made sure suspend can't exit early if get spurious signal
366 * Revision 1.71 2001/09/18 05:56:03 robertj
367 * Fixed numerous problems with thread suspend/resume and signals handling.
369 * Revision 1.70 2001/09/10 03:03:02 robertj
370 * Major change to fix problem with error codes being corrupted in a
371 * PChannel when have simultaneous reads and writes in threads.
372 * Changed threading so does not actually start thread until Resume(), makes
373 * the logic of start up much simpler and more portable.
374 * Quite a bit of tidyin up of the pthreads code.
376 * Revision 1.69 2001/08/30 08:57:40 robertj
377 * Changed calls to usleep to be PThread::Yield(), normalising single
378 * timeslice process swap out.
380 * Revision 1.68 2001/08/20 06:55:45 robertj
381 * Fixed ability to have PMutex::Wait() with times less than one second.
382 * Fixed small error in return value of block on I/O function, not critical.
384 * Revision 1.67 2001/08/07 02:50:03 craigs
385 * Fixed potential race condition in IO blocking
387 * Revision 1.66 2001/07/09 13:23:37 rogerh
388 * Fix a subtle bug in semaphore wait which showed up on FreeBSD
390 * Revision 1.65 2001/05/29 00:49:18 robertj
391 * Added ability to put in a printf %x in thread name to get thread object
392 * address into user settable thread name.
394 * Revision 1.64 2001/05/23 00:18:55 robertj
395 * Added support for real time threads, thanks Erland Lewin.
397 * Revision 1.63 2001/04/20 09:27:25 robertj
398 * Fixed previous change for auto delete threads, must have thread ID zeroed.
400 * Revision 1.62 2001/04/20 09:09:05 craigs
401 * Removed possible race condition whilst shutting down threads
403 * Revision 1.61 2001/03/20 06:44:25 robertj
404 * Lots of changes to fix the problems with terminating threads that are I/O
405 * blocked, especially when doing orderly shutdown of service via SIGTERM.
407 * Revision 1.60 2001/03/14 01:16:11 robertj
408 * Fixed signals processing, now uses housekeeping thread to handle signals
409 * synchronously. This also fixes issues with stopping PServiceProcess.
411 * Revision 1.59 2001/02/25 19:39:42 rogerh
412 * Use a Semaphore on Mac OS X to support threads which are started as 'suspended'
414 * Revision 1.58 2001/02/24 14:49:22 rogerh
415 * Add missing bracket
417 * Revision 1.57 2001/02/24 13:29:34 rogerh
418 * Mac OS X change to avoid Assertion
420 * Revision 1.56 2001/02/24 13:24:24 rogerh
421 * Add PThread support for Mac OS X and Darwin. There is one major issue. This
422 * OS does not suport pthread_kill() and sigwait() so we cannot support the
423 * Suspend() and Resume() functions to start and stop threads and we cannot
424 * create new threads in 'suspended' mode.
425 * Calling Suspend() raises an assertion. Calling Resume() does nothing.
426 * Threads started in 'suspended' mode start immediatly.
428 * Revision 1.55 2001/02/21 22:48:42 robertj
429 * Fixed incorrect test in PSemaphore::WillBlock() just added, thank Artis Kugevics.
431 * Revision 1.54 2001/02/20 00:21:14 robertj
432 * Fixed major bug in PSemapahore::WillBlock(), thanks Tomas Heran.
434 * Revision 1.53 2000/12/21 12:36:32 craigs
435 * Removed potential to stop threads twice
437 * Revision 1.52 2000/12/05 08:24:50 craigs
438 * Fixed problem with EINTR causing havoc
440 * Revision 1.51 2000/11/16 11:06:38 rogerh
441 * Add a better fix for the "user signal 2" aborts seen on FreeBSD 4.2 and above.
442 * We need to sched_yeild() after the pthread_create() to make sure the new thread
443 * actually has a chance to execute. The abort problem was caused when the
444 * resume signal was issued before the thread was ready for it.
446 * Revision 1.50 2000/11/12 23:30:02 craigs
447 * Added extra WaitForTermination to assist bug location
449 * Revision 1.49 2000/11/12 08:16:07 rogerh
450 * This change and the previous change, make pthreads work on FreeBSD 4.2.
451 * FreeBSD has improved its thread signal handling and now correctly generates a
452 * SIGUSR2 signal on a thread (the Resume Signal). However there was no handler
453 * for this signal and applications would abort with "User signal 2".
454 * So, a dummy sigResumeHandler has been added.
456 * Revision 1.48 2000/11/12 07:57:45 rogerh
457 * *** empty log message ***
459 * Revision 1.47 2000/10/31 08:09:51 rogerh
460 * Change return type of PX_GetThreadId() to save unnecessary typecasting
462 * Revision 1.46 2000/10/31 07:52:06 rogerh
463 * Add type casts to allow the code to compile on FreeBSD 4.1.1
465 * Revision 1.45 2000/10/30 05:48:33 robertj
466 * Added assert when get nested mutex.
468 * Revision 1.44 2000/10/24 03:32:40 robertj
469 * Fixed problem where thread that uses PThread::Current() in dtor crashes.
471 * Revision 1.43 2000/10/20 06:11:48 robertj
472 * Added function to change auto delete flag on a thread.
474 * Revision 1.42 2000/09/20 04:24:09 craigs
475 * Added extra tracing, and removed segv on exit when using tracing
477 * Revision 1.41 2000/06/21 01:01:22 robertj
478 * AIX port, thanks Wolfgang Platzer (wolfgang.platzer@infonova.at).
480 * Revision 1.40 2000/04/13 07:21:10 rogerh
481 * Fix typo in #defined
483 * Revision 1.39 2000/04/11 11:38:49 rogerh
484 * More NetBSD Pthread changes
486 * Revision 1.38 2000/04/10 11:47:02 rogerh
487 * Add initial NetBSD pthreads support
489 * Revision 1.37 2000/04/06 12:19:49 rogerh
490 * Add Mac OS X support submitted by Kevin Packard
492 * Revision 1.36 2000/03/20 22:56:34 craigs
493 * Fixed problems with race conditions caused by testing or changing
494 * attributes on a terminated thread. Only occured on a fast machine!
496 * Revision 1.35 2000/03/17 03:45:40 craigs
497 * Fixed problem with connect call hanging
499 * Revision 1.34 2000/03/08 12:17:09 rogerh
500 * Add OpenBSD support
502 * Revision 1.33 2000/02/29 13:18:21 robertj
503 * Added named threads to tracing, thanks to Dave Harvey
505 * Revision 1.32 2000/01/20 08:20:57 robertj
506 * FreeBSD v3 compatibility changes, thanks Roger Hardiman & Motonori Shindo
508 * Revision 1.31 1999/11/18 14:02:57 craigs
509 * Fixed problem with houskeeping thread termination
511 * Revision 1.30 1999/11/15 01:12:56 craigs
512 * Fixed problem with PSemaphore::Wait consuming 100% CPU
514 * Revision 1.29 1999/10/30 13:44:11 craigs
515 * Added correct method of aborting socket operations asynchronously
517 * Revision 1.28 1999/10/24 13:03:30 craigs
518 * Changed to capture io break signal
520 * Revision 1.27 1999/09/23 06:52:16 robertj
521 * Changed PSemaphore to use Posix semaphores.
523 * Revision 1.26 1999/09/03 02:26:25 robertj
524 * Changes to aid in breaking I/O locks on thread termination. Still needs more work esp in BSD!
526 * Revision 1.25 1999/09/02 11:56:35 robertj
527 * Fixed problem with destroying PMutex that is already locked.
529 * Revision 1.24 1999/08/24 13:40:56 craigs
530 * Fixed problem with condwait destorys failing on linux
532 * Revision 1.23 1999/08/23 05:33:45 robertj
533 * Made last threading changes Linux only.
535 * Revision 1.22 1999/08/23 05:14:13 robertj
536 * Removed blocking of interrupt signals as does not work in Linux threads.
538 * Revision 1.21 1999/07/30 00:40:32 robertj
539 * Fixed problem with signal variable in non-Linux platforms
541 * Revision 1.20 1999/07/19 01:32:24 craigs
542 * Changed signals used in pthreads code, is used by linux version.
544 * Revision 1.19 1999/07/15 13:10:55 craigs
545 * Fixed problem with EINTR in nontimed sempahore waits
547 * Revision 1.18 1999/07/15 13:05:33 robertj
548 * Fixed problem with getting EINTR in semaphore wait, is normal, not error.
550 * Revision 1.17 1999/07/11 13:42:13 craigs
551 * pthreads support for Linux
553 * Revision 1.16 1999/05/12 03:29:20 robertj
554 * Fixed problem with semaphore free, done at wrong time.
556 * Revision 1.15 1999/04/29 08:41:26 robertj
557 * Fixed problems with uninitialised mutexes in PProcess.
559 * Revision 1.14 1999/03/16 10:54:16 robertj
560 * Added parameterless version of WaitForTermination.
562 * Revision 1.13 1999/03/16 10:30:37 robertj
563 * Added missing PThread::WaitForTermination function.
565 * Revision 1.12 1999/01/12 12:09:51 robertj
566 * Removed redundent member variable, was in common.
567 * Fixed BSD threads compatibility.
569 * Revision 1.11 1999/01/11 12:05:56 robertj
570 * Fixed some more race conditions in threads.
572 * Revision 1.10 1999/01/11 03:42:26 robertj
573 * Fixed problem with destroying thread automatically.
575 * Revision 1.9 1999/01/09 03:37:28 robertj
576 * Fixed problem with closing thread waiting on semaphore.
577 * Improved efficiency of mutex to use pthread functions directly.
579 * Revision 1.8 1999/01/08 01:31:03 robertj
580 * Support for pthreads under FreeBSD
582 * Revision 1.7 1998/12/15 12:41:07 robertj
583 * Fixed signal handling so can now ^C a pthread version.
585 * Revision 1.6 1998/11/05 09:45:04 robertj
586 * Removed StartImmediate option in thread construction.
588 * Revision 1.5 1998/09/24 04:12:25 robertj
589 * Added open software license.
593 #include <ptlib/socket.h>
594 #include <sched.h> // for sched_yield
595 #include <pthread.h>
596 #include <sys/resource.h>
598 #ifdef P_RTEMS
599 #define SUSPEND_SIG SIGALRM
600 #include <sched.h>
601 #else
602 #define SUSPEND_SIG SIGVTALRM
603 #endif
605 #ifdef P_MACOSX
606 #include <mach/mach.h>
607 #include <mach/thread_policy.h>
608 #include <sys/param.h>
609 #include <sys/sysctl.h>
610 // going to need the main thread for adjusting relative priority
611 static pthread_t baseThread;
612 #endif
614 #ifdef P_HAS_SEMAPHORES_XPG6
615 #include "semaphore.h"
616 #endif
618 int PX_NewHandle(const char *, int);
620 #define PPThreadKill(id, sig) PProcess::Current().PThreadKill(id, sig)
623 #define PAssertPTHREAD(func, args) \
625 unsigned threadOpRetry = 0; \
626 while (PAssertThreadOp(func args, threadOpRetry, #func, __FILE__, __LINE__)); \
629 static BOOL PAssertThreadOp(int retval,
630 unsigned & retry,
631 const char * funcname,
632 const char * file,
633 unsigned line)
635 if (retval == 0) {
636 PTRACE_IF(2, retry > 0, "PWLib\t" << funcname << " required " << retry << " retries!");
637 return FALSE;
640 if (errno == EINTR || errno == EAGAIN) {
641 if (++retry < 1000) {
642 #if defined(P_RTEMS)
643 sched_yield();
644 #else
645 usleep(10000); // Basically just swap out thread to try and clear blockage
646 #endif
647 return TRUE; // Return value to try again
649 // Give up and assert
652 PAssertFunc(file, line, NULL, psprintf("Function %s failed", funcname));
653 return FALSE;
657 PDECLARE_CLASS(PHouseKeepingThread, PThread)
658 public:
659 PHouseKeepingThread()
660 : PThread(1000, NoAutoDeleteThread, NormalPriority, "Housekeeper")
661 { closing = FALSE; Resume(); }
663 void Main();
664 void SetClosing() { closing = TRUE; }
666 protected:
667 BOOL closing;
671 static pthread_mutex_t MutexInitialiser = PTHREAD_MUTEX_INITIALIZER;
674 #define new PNEW
677 void PHouseKeepingThread::Main()
679 PProcess & process = PProcess::Current();
681 while (!closing) {
682 PTimeInterval delay = process.timers.Process();
684 process.breakBlock.Wait(delay);
686 process.PXCheckSignals();
691 void PProcess::SignalTimerChange()
693 if (housekeepingThread == NULL) {
694 #if PMEMORY_CHECK
695 BOOL oldIgnoreAllocations = PMemoryHeap::SetIgnoreAllocations(TRUE);
696 #endif
697 housekeepingThread = new PHouseKeepingThread;
698 #if PMEMORY_CHECK
699 PMemoryHeap::SetIgnoreAllocations(oldIgnoreAllocations);
700 #endif
703 breakBlock.Signal();
707 void PProcess::Construct()
709 #ifndef P_RTEMS
710 // get the file descriptor limit
711 struct rlimit rl;
712 PAssertOS(getrlimit(RLIMIT_NOFILE, &rl) == 0);
713 maxHandles = rl.rlim_cur;
714 PTRACE(4, "PWLib\tMaximum per-process file handles is " << maxHandles);
715 #else
716 maxHandles = 500; // arbitrary value
717 #endif
719 // initialise the housekeeping thread
720 housekeepingThread = NULL;
722 #ifdef P_MACOSX
723 // records the main thread for priority adjusting
724 baseThread = pthread_self();
725 #endif
727 CommonConstruct();
731 BOOL PProcess::SetMaxHandles(int newMax)
733 #ifndef P_RTEMS
734 // get the current process limit
735 struct rlimit rl;
736 PAssertOS(getrlimit(RLIMIT_NOFILE, &rl) == 0);
738 // set the new current limit
739 rl.rlim_cur = newMax;
740 if (setrlimit(RLIMIT_NOFILE, &rl) == 0) {
741 PAssertOS(getrlimit(RLIMIT_NOFILE, &rl) == 0);
742 maxHandles = rl.rlim_cur;
743 if (maxHandles == newMax) {
744 PTRACE(2, "PWLib\tNew maximum per-process file handles set to " << maxHandles);
745 return TRUE;
748 #endif // !P_RTEMS
750 PTRACE(1, "PWLib\tCannot set per-process file handle limit to "
751 << newMax << " (is " << maxHandles << ") - check permissions");
752 return FALSE;
756 PProcess::~PProcess()
758 PreShutdown();
760 // Don't wait for housekeeper to stop if Terminate() is called from it.
761 if (housekeepingThread != NULL && PThread::Current() != housekeepingThread) {
762 housekeepingThread->SetClosing();
763 SignalTimerChange();
764 housekeepingThread->WaitForTermination();
765 delete housekeepingThread;
767 CommonDestruct();
769 PTRACE(5, "PWLib\tDestroyed process " << this);
772 BOOL PProcess::PThreadKill(pthread_t id, unsigned sig)
774 PWaitAndSignal m(threadMutex);
776 if (!activeThreads.Contains((unsigned)id))
777 return FALSE;
779 return pthread_kill(id, sig) == 0;
783 //////////////////////////////////////////////////////////////////////////////
785 PThread::PThread()
787 // see InitialiseProcessThread()
791 void PThread::InitialiseProcessThread()
793 autoDelete = FALSE;
795 PX_origStackSize = 0;
796 PX_threadId = pthread_self();
797 PX_priority = NormalPriority;
798 PX_suspendCount = 0;
800 #ifndef P_HAS_SEMAPHORES
801 PX_waitingSemaphore = NULL;
802 PX_WaitSemMutex = MutexInitialiser;
803 #endif
805 PX_suspendMutex = MutexInitialiser;
807 #ifdef P_RTEMS
808 PAssertOS(socketpair(AF_INET,SOCK_STREAM,0,unblockPipe) == 0);
809 #else
810 PAssertOS(::pipe(unblockPipe) == 0);
811 #endif
813 ((PProcess *)this)->activeThreads.DisallowDeleteObjects();
814 ((PProcess *)this)->activeThreads.SetAt((unsigned)PX_threadId, this);
816 PX_firstTimeStart = FALSE;
818 traceBlockIndentLevel = 0;
822 PThread::PThread(PINDEX stackSize,
823 AutoDeleteFlag deletion,
824 Priority priorityLevel,
825 const PString & name)
826 : threadName(name)
828 autoDelete = (deletion == AutoDeleteThread);
830 PAssert(stackSize > 0, PInvalidParameter);
831 PX_origStackSize = stackSize;
832 PX_threadId = 0;
833 PX_priority = priorityLevel;
834 PX_suspendCount = 1;
836 #ifndef P_HAS_SEMAPHORES
837 PX_waitingSemaphore = NULL;
838 PX_WaitSemMutex = MutexInitialiser;
839 #endif
841 PX_suspendMutex = MutexInitialiser;
843 #ifdef P_RTEMS
844 PAssertOS(socketpair(AF_INET,SOCK_STREAM,0,unblockPipe) == 0);
845 #else
846 PAssertOS(::pipe(unblockPipe) == 0);
847 #endif
848 PX_NewHandle("Thread unblock pipe", PMAX(unblockPipe[0], unblockPipe[1]));
850 // new thread is actually started the first time Resume() is called.
851 PX_firstTimeStart = TRUE;
853 traceBlockIndentLevel = 0;
855 PTRACE(5, "PWLib\tCreated thread " << this << ' ' << threadName);
859 PThread::~PThread()
861 if (PX_threadId != 0 && PX_threadId != pthread_self())
862 Terminate();
864 PAssertPTHREAD(::close, (unblockPipe[0]));
865 PAssertPTHREAD(::close, (unblockPipe[1]));
867 #ifndef P_HAS_SEMAPHORES
868 pthread_mutex_destroy(&PX_WaitSemMutex);
869 #endif
871 // If the mutex was not locked, the unlock will fail */
872 pthread_mutex_trylock(&PX_suspendMutex);
873 pthread_mutex_unlock(&PX_suspendMutex);
874 pthread_mutex_destroy(&PX_suspendMutex);
876 if (this != &PProcess::Current())
877 PTRACE(1, "PWLib\tDestroyed thread " << this << ' ' << threadName << "(id = " << ::hex << PX_threadId << ::dec << ")");
878 else
879 PProcessInstance = NULL;
883 void PThread::Restart()
885 if (!IsTerminated())
886 return;
888 pthread_attr_t threadAttr;
889 pthread_attr_init(&threadAttr);
890 pthread_attr_setdetachstate(&threadAttr, PTHREAD_CREATE_DETACHED);
892 #if defined(P_LINUX)
894 // Set a decent (256K) stack size that won't eat all virtual memory
895 pthread_attr_setstacksize(&threadAttr, 16*PTHREAD_STACK_MIN);
898 Set realtime scheduling if our effective user id is root (only then is this
899 allowed) AND our priority is Highest.
900 As far as I can see, we could use either SCHED_FIFO or SCHED_RR here, it
901 doesn't matter.
902 I don't know if other UNIX OSs have SCHED_FIFO and SCHED_RR as well.
904 WARNING: a misbehaving thread (one that never blocks) started with Highest
905 priority can hang the entire machine. That is why root permission is
906 neccessary.
908 if ((geteuid() == 0) && (PX_priority == HighestPriority))
909 PAssertPTHREAD(pthread_attr_setschedpolicy, (&threadAttr, SCHED_FIFO));
910 #elif defined(P_RTEMS)
911 pthread_attr_setstacksize(&threadAttr, 2*PTHREAD_MINIMUM_STACK_SIZE);
912 pthread_attr_setinheritsched(&threadAttr, PTHREAD_EXPLICIT_SCHED);
913 pthread_attr_setschedpolicy(&threadAttr, SCHED_OTHER);
914 struct sched_param sched_param;
915 sched_param.sched_priority = 125; /* set medium priority */
916 pthread_attr_setschedparam(&threadAttr, &sched_param);
917 #endif
919 PProcess & process = PProcess::Current();
920 PINDEX newHighWaterMark = 0;
921 static PINDEX highWaterMark = 0;
923 // lock the thread list
924 process.threadMutex.Wait();
926 // create the thread
927 PAssertPTHREAD(pthread_create, (&PX_threadId, &threadAttr, PX_ThreadStart, this));
929 // put the thread into the thread list
930 process.activeThreads.SetAt((unsigned)PX_threadId, this);
931 if (process.activeThreads.GetSize() > highWaterMark)
932 newHighWaterMark = highWaterMark = process.activeThreads.GetSize();
934 // unlock the thread list
935 process.threadMutex.Signal();
937 PTRACE_IF(4, newHighWaterMark > 0, "PWLib\tThread high water mark set: " << newHighWaterMark);
939 #ifdef P_MACOSX
940 if (PX_priority == HighestPriority) {
941 PTRACE(1, "set thread to have the highest priority (MACOSX)");
942 SetPriority(HighestPriority);
944 #endif
948 void PX_SuspendSignalHandler(int)
950 PThread * thread = PThread::Current();
951 if (thread == NULL)
952 return;
954 BOOL notResumed = TRUE;
955 while (notResumed) {
956 BYTE ch;
957 notResumed = ::read(thread->unblockPipe[0], &ch, 1) < 0 && errno == EINTR;
958 #if !( defined(P_NETBSD) && defined(P_NO_CANCEL) )
959 pthread_testcancel();
960 #endif
965 void PThread::Suspend(BOOL susp)
967 PAssertPTHREAD(pthread_mutex_lock, (&PX_suspendMutex));
969 // Check for start up condition, first time Resume() is called
970 if (PX_firstTimeStart) {
971 if (susp)
972 PX_suspendCount++;
973 else {
974 if (PX_suspendCount > 0)
975 PX_suspendCount--;
976 if (PX_suspendCount == 0) {
977 PX_firstTimeStart = FALSE;
978 Restart();
982 PAssertPTHREAD(pthread_mutex_unlock, (&PX_suspendMutex));
983 return;
986 #if defined(P_MACOSX) && (P_MACOSX <= 55)
987 // Suspend - warn the user with an Assertion
988 PAssertAlways("Cannot suspend threads on Mac OS X due to lack of pthread_kill()");
989 #else
990 if (PPThreadKill(PX_threadId, 0)) {
992 // if suspending, then see if already suspended
993 if (susp) {
994 PX_suspendCount++;
995 if (PX_suspendCount == 1) {
996 if (PX_threadId != pthread_self()) {
997 signal(SUSPEND_SIG, PX_SuspendSignalHandler);
998 PPThreadKill(PX_threadId, SUSPEND_SIG);
1000 else {
1001 PAssertPTHREAD(pthread_mutex_unlock, (&PX_suspendMutex));
1002 PX_SuspendSignalHandler(SUSPEND_SIG);
1003 return; // Mutex already unlocked
1008 // if resuming, then see if to really resume
1009 else if (PX_suspendCount > 0) {
1010 PX_suspendCount--;
1011 if (PX_suspendCount == 0)
1012 PXAbortBlock();
1016 PAssertPTHREAD(pthread_mutex_unlock, (&PX_suspendMutex));
1017 #endif // P_MACOSX
1021 void PThread::Resume()
1023 Suspend(FALSE);
1027 BOOL PThread::IsSuspended() const
1029 if (PX_firstTimeStart)
1030 return TRUE;
1032 if (IsTerminated())
1033 return FALSE;
1035 PAssertPTHREAD(pthread_mutex_lock, ((pthread_mutex_t *)&PX_suspendMutex));
1036 BOOL suspended = PX_suspendCount != 0;
1037 PAssertPTHREAD(pthread_mutex_unlock, ((pthread_mutex_t *)&PX_suspendMutex));
1038 return suspended;
1042 void PThread::SetAutoDelete(AutoDeleteFlag deletion)
1044 PAssert(deletion != AutoDeleteThread || this != &PProcess::Current(), PLogicError);
1045 autoDelete = deletion == AutoDeleteThread;
1048 #ifdef P_MACOSX
1049 // obtain thread priority of the main thread
1050 static unsigned long
1051 GetThreadBasePriority ()
1053 thread_basic_info_data_t threadInfo;
1054 policy_info_data_t thePolicyInfo;
1055 unsigned int count;
1057 if (baseThread == 0) {
1058 return 0;
1061 // get basic info
1062 count = THREAD_BASIC_INFO_COUNT;
1063 thread_info (pthread_mach_thread_np (baseThread), THREAD_BASIC_INFO,
1064 (integer_t*)&threadInfo, &count);
1066 switch (threadInfo.policy) {
1067 case POLICY_TIMESHARE:
1068 count = POLICY_TIMESHARE_INFO_COUNT;
1069 thread_info(pthread_mach_thread_np (baseThread),
1070 THREAD_SCHED_TIMESHARE_INFO,
1071 (integer_t*)&(thePolicyInfo.ts), &count);
1072 return thePolicyInfo.ts.base_priority;
1074 case POLICY_FIFO:
1075 count = POLICY_FIFO_INFO_COUNT;
1076 thread_info(pthread_mach_thread_np (baseThread),
1077 THREAD_SCHED_FIFO_INFO,
1078 (integer_t*)&(thePolicyInfo.fifo), &count);
1079 if (thePolicyInfo.fifo.depressed)
1080 return thePolicyInfo.fifo.depress_priority;
1081 return thePolicyInfo.fifo.base_priority;
1083 case POLICY_RR:
1084 count = POLICY_RR_INFO_COUNT;
1085 thread_info(pthread_mach_thread_np (baseThread),
1086 THREAD_SCHED_RR_INFO,
1087 (integer_t*)&(thePolicyInfo.rr), &count);
1088 if (thePolicyInfo.rr.depressed)
1089 return thePolicyInfo.rr.depress_priority;
1090 return thePolicyInfo.rr.base_priority;
1093 return 0;
1095 #endif
1097 void PThread::SetPriority(Priority priorityLevel)
1099 PX_priority = priorityLevel;
1101 #if defined(P_LINUX)
1102 if (IsTerminated())
1103 return;
1105 struct sched_param sched_param;
1107 if ((priorityLevel == HighestPriority) && (geteuid() == 0) ) {
1108 sched_param.sched_priority = sched_get_priority_min( SCHED_FIFO );
1110 PAssertPTHREAD(pthread_setschedparam, (PX_threadId, SCHED_FIFO, &sched_param));
1112 else if (priorityLevel != HighestPriority) {
1113 /* priority 0 is the only permitted value for the SCHED_OTHER scheduler */
1114 sched_param.sched_priority = 0;
1116 PAssertPTHREAD(pthread_setschedparam, (PX_threadId, SCHED_OTHER, &sched_param));
1118 #endif
1120 #if defined(P_MACOSX)
1121 if (IsTerminated())
1122 return;
1124 if (priorityLevel == HighestPriority) {
1125 /* get fixed priority */
1127 int result;
1129 thread_extended_policy_data_t theFixedPolicy;
1130 thread_precedence_policy_data_t thePrecedencePolicy;
1131 long relativePriority;
1133 theFixedPolicy.timeshare = false; // set to true for a non-fixed thread
1134 result = thread_policy_set (pthread_mach_thread_np(PX_threadId),
1135 THREAD_EXTENDED_POLICY,
1136 (thread_policy_t)&theFixedPolicy,
1137 THREAD_EXTENDED_POLICY_COUNT);
1138 if (result != KERN_SUCCESS) {
1139 PTRACE(1, "thread_policy - Couldn't set thread as fixed priority.");
1142 // set priority
1144 // precedency policy's "importance" value is relative to
1145 // spawning thread's priority
1147 relativePriority = 62 - GetThreadBasePriority();
1148 PTRACE(1, "relativePriority is " << relativePriority << " base priority is " << GetThreadBasePriority());
1150 thePrecedencePolicy.importance = relativePriority;
1151 result = thread_policy_set (pthread_mach_thread_np(PX_threadId),
1152 THREAD_PRECEDENCE_POLICY,
1153 (thread_policy_t)&thePrecedencePolicy,
1154 THREAD_PRECEDENCE_POLICY_COUNT);
1155 if (result != KERN_SUCCESS) {
1156 PTRACE(1, "thread_policy - Couldn't set thread priority.");
1160 #endif
1164 PThread::Priority PThread::GetPriority() const
1166 #if defined(LINUX)
1167 int schedulingPolicy;
1168 struct sched_param schedParams;
1170 PAssertPTHREAD(pthread_getschedparam, (PX_threadId, &schedulingPolicy, &schedParams));
1172 switch( schedulingPolicy )
1174 case SCHED_OTHER:
1175 break;
1177 case SCHED_FIFO:
1178 case SCHED_RR:
1179 return HighestPriority;
1181 default:
1182 /* Unknown scheduler. We don't know what priority this thread has. */
1183 PTRACE(1, "PWLib\tPThread::GetPriority: unknown scheduling policy #" << schedulingPolicy);
1185 #endif
1187 return NormalPriority; /* as good a guess as any */
1191 #ifndef P_HAS_SEMAPHORES
1192 void PThread::PXSetWaitingSemaphore(PSemaphore * sem)
1194 PAssertPTHREAD(pthread_mutex_lock, (&PX_WaitSemMutex));
1195 PX_waitingSemaphore = sem;
1196 PAssertPTHREAD(pthread_mutex_unlock, (&PX_WaitSemMutex));
1198 #endif
1201 #ifdef P_GNU_PTH
1202 // GNU PTH threads version (used by NetBSD)
1203 // Taken from NetBSD pkg patches
1204 void PThread::Sleep(const PTimeInterval & timeout)
1206 PTime lastTime;
1207 PTime targetTime = PTime() + timeout;
1209 sched_yield();
1210 lastTime = PTime();
1212 while (lastTime < targetTime) {
1213 P_timeval tval = targetTime - lastTime;
1214 if (select(0, NULL, NULL, NULL, tval) < 0 && errno != EINTR)
1215 break;
1217 pthread_testcancel();
1219 lastTime = PTime();
1223 #else
1224 // Normal Posix threads version
1225 void PThread::Sleep(const PTimeInterval & timeout)
1227 PTime lastTime;
1228 PTime targetTime = lastTime + timeout;
1229 do {
1230 P_timeval tval = targetTime - lastTime;
1231 if (select(0, NULL, NULL, NULL, tval) < 0 && errno != EINTR)
1232 break;
1234 #if !( defined(P_NETBSD) && defined(P_NO_CANCEL) )
1235 pthread_testcancel();
1236 #endif
1238 lastTime = PTime();
1239 } while (lastTime < targetTime);
1241 #endif
1243 void PThread::Yield()
1245 sched_yield();
1249 PThread * PThread::Current()
1251 PProcess & process = PProcess::Current();
1252 process.threadMutex.Wait();
1253 PThread * thread = process.activeThreads.GetAt((unsigned)pthread_self());
1254 process.threadMutex.Signal();
1255 return thread;
1259 void PThread::Terminate()
1261 if (PX_origStackSize <= 0)
1262 return;
1264 // don't use PThread::Current, as the thread may already not be in the
1265 // active threads list
1266 if (PX_threadId == pthread_self()) {
1267 pthread_exit(0);
1268 return;
1271 if (IsTerminated())
1272 return;
1274 PTRACE(2, "PWLib\tForcing termination of thread " << (void *)this);
1276 PXAbortBlock();
1277 WaitForTermination(20);
1279 #if !defined(P_HAS_SEMAPHORES) && !defined(P_HAS_NAMED_SEMAPHORES)
1280 PAssertPTHREAD(pthread_mutex_lock, (&PX_WaitSemMutex));
1281 if (PX_waitingSemaphore != NULL) {
1282 PAssertPTHREAD(pthread_mutex_lock, (&PX_waitingSemaphore->mutex));
1283 PX_waitingSemaphore->queuedLocks--;
1284 PAssertPTHREAD(pthread_mutex_unlock, (&PX_waitingSemaphore->mutex));
1285 PX_waitingSemaphore = NULL;
1287 PAssertPTHREAD(pthread_mutex_unlock, (&PX_WaitSemMutex));
1288 #endif
1290 #if ( defined(P_NETBSD) && defined(P_NO_CANCEL) )
1291 PPThreadKill(PX_threadId,SIGKILL);
1292 #else
1293 if (PX_threadId) {
1294 pthread_cancel(PX_threadId);
1296 #endif
1300 BOOL PThread::IsTerminated() const
1302 pthread_t id = PX_threadId;
1303 return (id == 0) || !PPThreadKill(id, 0);
1307 void PThread::WaitForTermination() const
1309 if (this == Current()) {
1310 PTRACE(2, "WaitForTermination short circuited");
1311 return;
1314 PXAbortBlock(); // this assist in clean shutdowns on some systems
1316 while (!IsTerminated()) {
1317 Sleep(10); // sleep for 10ms. This slows down the busy loop removing 100%
1318 // CPU usage and also yeilds so other threads can run.
1323 BOOL PThread::WaitForTermination(const PTimeInterval & maxWait) const
1325 if (this == Current()) {
1326 PTRACE(2, "WaitForTermination(t) short circuited");
1327 return TRUE;
1330 PTRACE(6, "PWLib\tWaitForTermination(" << maxWait << ')');
1332 PXAbortBlock(); // this assist in clean shutdowns on some systems
1333 PTimer timeout = maxWait;
1334 while (!IsTerminated()) {
1335 if (timeout == 0)
1336 return FALSE;
1337 Sleep(10); // sleep for 10ms. This slows down the busy loop removing 100%
1338 // CPU usage and also yeilds so other threads can run.
1340 return TRUE;
1344 void * PThread::PX_ThreadStart(void * arg)
1346 PThread * thread = (PThread *)arg;
1347 //don't need to detach the the thread, it was created in the PTHREAD_CREATE_DETACHED state
1348 // Added this to guarantee that the thread creation (PThread::Restart)
1349 // has completed before we start the thread. Then the PX_threadId has
1350 // been set.
1351 pthread_mutex_lock(&thread->PX_suspendMutex);
1352 thread->SetThreadName(thread->GetThreadName());
1353 pthread_mutex_unlock(&thread->PX_suspendMutex);
1355 // make sure the cleanup routine is called when the thread exits
1356 pthread_cleanup_push(&PThread::PX_ThreadEnd, arg);
1358 PTRACE(5, "PWLib\tStarted thread " << thread << ' ' << thread->threadName);
1360 // now call the the thread main routine
1361 thread->Main();
1363 // execute the cleanup routine
1364 pthread_cleanup_pop(1);
1366 return NULL;
1370 void PThread::PX_ThreadEnd(void * arg)
1372 PProcess & process = PProcess::Current();
1373 process.threadMutex.Wait();
1375 PThread * thread = (PThread *)arg;
1376 pthread_t id = thread->GetThreadId();
1377 if (id == 0) {
1378 // Don't know why, but pthreads under Linux at least can call this function
1379 // multiple times! Probably a bug, but we have to allow for it.
1380 process.threadMutex.Signal();
1381 PTRACE(2, "PWLib\tAttempted to multiply end thread " << thread << " ThreadID=" << (void *)id);
1382 return;
1385 // remove this thread from the active thread list
1386 process.activeThreads.SetAt((unsigned)id, NULL);
1388 // delete the thread if required, note this is done this way to avoid
1389 // a race condition, the thread ID cannot be zeroed before the if!
1390 if (thread->autoDelete) {
1391 thread->PX_threadId = 0; // Prevent terminating terminated thread
1392 process.threadMutex.Signal();
1393 PTRACE(5, "PWLib\tEnded thread " << thread << ' ' << thread->threadName);
1395 /* It is now safe to delete this thread. Note that this thread
1396 is deleted after the process.threadMutex.Signal(), which means
1397 PWaitAndSignal(process.threadMutex) could not be used */
1398 delete thread;
1400 else {
1401 thread->PX_threadId = 0;
1402 PString threadName = thread->threadName;
1403 process.threadMutex.Signal();
1404 PTRACE(5, "PWLib\tEnded thread " << thread << ' ' << threadName);
1408 int PThread::PXBlockOnIO(int handle, int type, const PTimeInterval & timeout)
1410 PTRACE(7, "PWLib\tPThread::PXBlockOnIO(" << handle << ',' << type << ')');
1412 if ((handle < 0) || (handle >= PProcess::Current().GetMaxHandles())) {
1413 PTRACE(2, "PWLib\tAttempt to use illegal handle in PThread::PXBlockOnIO, handle=" << handle);
1414 errno = EBADF;
1415 return -1;
1418 // make sure we flush the buffer before doing a write
1419 P_fd_set read_fds;
1420 P_fd_set write_fds;
1421 P_fd_set exception_fds;
1423 int retval;
1424 do {
1425 switch (type) {
1426 case PChannel::PXReadBlock:
1427 case PChannel::PXAcceptBlock:
1428 read_fds = handle;
1429 write_fds.Zero();
1430 exception_fds.Zero();
1431 break;
1432 case PChannel::PXWriteBlock:
1433 read_fds.Zero();
1434 write_fds = handle;
1435 exception_fds.Zero();
1436 break;
1437 case PChannel::PXConnectBlock:
1438 read_fds.Zero();
1439 write_fds = handle;
1440 exception_fds = handle;
1441 break;
1442 default:
1443 PAssertAlways(PLogicError);
1444 return 0;
1447 // include the termination pipe into all blocking I/O functions
1448 read_fds += unblockPipe[0];
1450 P_timeval tval = timeout;
1451 retval = ::select(PMAX(handle, unblockPipe[0])+1,
1452 read_fds, write_fds, exception_fds, tval);
1453 } while (retval < 0 && errno == EINTR);
1455 if ((retval == 1) && read_fds.IsPresent(unblockPipe[0])) {
1456 BYTE ch;
1457 ::read(unblockPipe[0], &ch, 1);
1458 errno = EINTR;
1459 retval = -1;
1460 PTRACE(6, "PWLib\tUnblocked I/O fd=" << unblockPipe[0]);
1463 return retval;
1466 void PThread::PXAbortBlock() const
1468 static BYTE ch = 0;
1469 ::write(unblockPipe[1], &ch, 1);
1470 PTRACE(6, "PWLib\tUnblocking I/O fd=" << unblockPipe[0] << " thread=" << GetThreadName());
1474 ///////////////////////////////////////////////////////////////////////////////
1476 PSemaphore::PSemaphore(PXClass pxc)
1478 pxClass = pxc;
1480 // these should never be used, as this constructor is
1481 // only used for PMutex and PSyncPoint and they have their
1482 // own copy constructors
1484 initialVar = maxCountVar = 0;
1486 if(pxClass == PXSemaphore) {
1487 #if defined(P_HAS_SEMAPHORES)
1488 /* call sem_init, otherwise sem_destroy fails*/
1489 PAssertPTHREAD(sem_init, (&semId, 0, 0));
1490 #elif defined(P_HAS_NAMED_SEMAPHORES)
1491 semId = CreateSem(0);
1492 #else
1493 currentCount = maximumCount = 0;
1494 queuedLocks = 0;
1495 pthread_mutex_init(&mutex, NULL);
1496 pthread_cond_init(&condVar, NULL);
1497 #endif
1502 PSemaphore::PSemaphore(unsigned initial, unsigned maxCount)
1504 pxClass = PXSemaphore;
1506 initialVar = initial;
1507 maxCountVar = maxCount;
1509 #if defined(P_HAS_SEMAPHORES)
1510 PAssertPTHREAD(sem_init, (&semId, 0, initial));
1511 #elif defined(P_HAS_NAMED_SEMAPHORES)
1512 semId = CreateSem(initialVar);
1513 #else
1514 PAssertPTHREAD(pthread_mutex_init, (&mutex, NULL));
1515 PAssertPTHREAD(pthread_cond_init, (&condVar, NULL));
1517 PAssert(maxCount > 0, "Invalid semaphore maximum.");
1518 if (initial > maxCount)
1519 initial = maxCount;
1521 currentCount = initial;
1522 maximumCount = maxCount;
1523 queuedLocks = 0;
1524 #endif
1528 PSemaphore::PSemaphore(const PSemaphore & sem)
1530 pxClass = sem.GetSemClass();
1532 initialVar = sem.GetInitial();
1533 maxCountVar = sem.GetMaxCount();
1535 if(pxClass == PXSemaphore) {
1536 #if defined(P_HAS_SEMAPHORES)
1537 PAssertPTHREAD(sem_init, (&semId, 0, initialVar));
1538 #elif defined(P_HAS_NAMED_SEMAPHORES)
1539 semId = CreateSem(initialVar);
1540 #else
1541 PAssertPTHREAD(pthread_mutex_init, (&mutex, NULL));
1542 PAssertPTHREAD(pthread_cond_init, (&condVar, NULL));
1544 PAssert(maxCountVar > 0, "Invalid semaphore maximum.");
1545 if (initialVar > maxCountVar)
1546 initialVar = maxCountVar;
1548 currentCount = initialVar;
1549 maximumCount = maxCountVar;
1550 queuedLocks = 0;
1551 #endif
1555 PSemaphore::~PSemaphore()
1557 if(pxClass == PXSemaphore) {
1558 #if defined(P_HAS_SEMAPHORES)
1559 PAssertPTHREAD(sem_destroy, (&semId));
1560 #elif defined(P_HAS_NAMED_SEMAPHORES)
1561 PAssertPTHREAD(sem_close, (semId));
1562 #else
1563 PAssert(queuedLocks == 0, "Semaphore destroyed with queued locks");
1564 PAssertPTHREAD(pthread_mutex_destroy, (&mutex));
1565 PAssertPTHREAD(pthread_cond_destroy, (&condVar));
1566 #endif
1570 #if defined(P_HAS_NAMED_SEMAPHORES)
1571 sem_t * PSemaphore::CreateSem(unsigned initialValue)
1573 sem_t *sem;
1575 // Since sem_open and sem_unlink are two operations, there is a small
1576 // window of opportunity that two simultaneous accesses may return
1577 // the same semaphore. Therefore, the static mutex is used to
1578 // prevent this, even if the chances are small
1579 static pthread_mutex_t semCreationMutex = PTHREAD_MUTEX_INITIALIZER;
1580 PAssertPTHREAD(pthread_mutex_lock, (&semCreationMutex));
1582 sem_unlink("/pwlib_sem");
1583 sem = sem_open("/pwlib_sem", (O_CREAT | O_EXCL), 700, initialValue);
1585 PAssertPTHREAD(pthread_mutex_unlock, (&semCreationMutex));
1587 PAssert(((int)sem != SEM_FAILED), "Couldn't create named semaphore");
1588 return sem;
1590 #endif
1592 void PSemaphore::Wait()
1594 #if defined(P_HAS_SEMAPHORES)
1595 PAssertPTHREAD(sem_wait, (&semId));
1596 #elif defined(P_HAS_NAMED_SEMAPHORES)
1597 PAssertPTHREAD(sem_wait, (semId));
1598 #else
1599 PAssertPTHREAD(pthread_mutex_lock, (&mutex));
1601 queuedLocks++;
1602 PThread::Current()->PXSetWaitingSemaphore(this);
1604 while (currentCount == 0) {
1605 int err = pthread_cond_wait(&condVar, &mutex);
1606 PAssert(err == 0 || err == EINTR, psprintf("wait error = %i", err));
1609 PThread::Current()->PXSetWaitingSemaphore(NULL);
1610 queuedLocks--;
1612 currentCount--;
1614 PAssertPTHREAD(pthread_mutex_unlock, (&mutex));
1615 #endif
1619 BOOL PSemaphore::Wait(const PTimeInterval & waitTime)
1621 if (waitTime == PMaxTimeInterval) {
1622 Wait();
1623 return TRUE;
1626 // create absolute finish time
1627 PTime finishTime;
1628 finishTime += waitTime;
1630 #if defined(P_HAS_SEMAPHORES)
1631 #ifdef P_HAS_SEMAPHORES_XPG6
1632 // use proper timed spinlocks if supported.
1633 // http://www.opengroup.org/onlinepubs/007904975/functions/sem_timedwait.html
1635 struct timespec absTime;
1636 absTime.tv_sec = finishTime.GetTimeInSeconds();
1637 absTime.tv_nsec = finishTime.GetMicrosecond() * 1000;
1639 if (sem_timedwait(&semId, &absTime) == 0) {
1640 return TRUE;
1642 else {
1643 return FALSE;
1646 #else
1647 // loop until timeout, or semaphore becomes available
1648 // don't use a PTimer, as this causes the housekeeping
1649 // thread to get very busy
1650 do {
1651 if (sem_trywait(&semId) == 0)
1652 return TRUE;
1654 #if defined(P_LINUX)
1655 // sched_yield in a tight loop is bad karma
1656 // for the linux scheduler: http://www.ussg.iu.edu/hypermail/linux/kernel/0312.2/1127.html
1657 PThread::Current()->Sleep(10);
1658 #else
1659 PThread::Yield();
1660 #endif
1661 } while (PTime() < finishTime);
1663 return FALSE;
1665 #endif
1666 #elif defined(P_HAS_NAMED_SEMAPHORES)
1667 do {
1668 if(sem_trywait(semId) == 0)
1669 return TRUE;
1670 PThread::Current()->Sleep(10);
1671 } while (PTime() < finishTime);
1673 return FALSE;
1674 #else
1676 struct timespec absTime;
1677 absTime.tv_sec = finishTime.GetTimeInSeconds();
1678 absTime.tv_nsec = finishTime.GetMicrosecond() * 1000;
1680 PAssertPTHREAD(pthread_mutex_lock, (&mutex));
1682 PThread * thread = PThread::Current();
1683 thread->PXSetWaitingSemaphore(this);
1684 queuedLocks++;
1686 BOOL ok = TRUE;
1687 while (currentCount == 0) {
1688 int err = pthread_cond_timedwait(&condVar, &mutex, &absTime);
1689 if (err == ETIMEDOUT) {
1690 ok = FALSE;
1691 break;
1693 else
1694 PAssert(err == 0 || err == EINTR, psprintf("timed wait error = %i", err));
1697 thread->PXSetWaitingSemaphore(NULL);
1698 queuedLocks--;
1700 if (ok)
1701 currentCount--;
1703 PAssertPTHREAD(pthread_mutex_unlock, ((pthread_mutex_t *)&mutex));
1705 return ok;
1706 #endif
1710 void PSemaphore::Signal()
1712 #if defined(P_HAS_SEMAPHORES)
1713 PAssertPTHREAD(sem_post, (&semId));
1714 #elif defined(P_HAS_NAMED_SEMAPHORES)
1715 PAssertPTHREAD(sem_post, (semId));
1716 #else
1717 PAssertPTHREAD(pthread_mutex_lock, (&mutex));
1719 if (currentCount < maximumCount)
1720 currentCount++;
1722 if (queuedLocks > 0)
1723 PAssertPTHREAD(pthread_cond_signal, (&condVar));
1725 PAssertPTHREAD(pthread_mutex_unlock, (&mutex));
1726 #endif
1730 BOOL PSemaphore::WillBlock() const
1732 #if defined(P_HAS_SEMAPHORES)
1733 if (sem_trywait((sem_t *)&semId) != 0) {
1734 PAssertOS(errno == EAGAIN || errno == EINTR);
1735 return TRUE;
1737 PAssertPTHREAD(sem_post, ((sem_t *)&semId));
1738 return FALSE;
1739 #elif defined(P_HAS_NAMED_SEMAPHORES)
1740 if (sem_trywait(semId) != 0) {
1741 PAssertOS(errno == EAGAIN || errno == EINTR);
1742 return TRUE;
1744 PAssertPTHREAD(sem_post, (semId));
1745 return FALSE;
1746 #else
1747 return currentCount == 0;
1748 #endif
1751 PTimedMutex::PTimedMutex()
1752 // : PSemaphore(PXMutex)
1754 #if P_HAS_RECURSIVE_MUTEX
1755 pthread_mutexattr_t attr;
1756 PAssertPTHREAD(pthread_mutexattr_init, (&attr));
1758 PAssertPTHREAD(pthread_mutexattr_settype, (&attr,
1759 #if P_HAS_RECURSIVE_MUTEX == 2
1760 PTHREAD_MUTEX_RECURSIVE
1761 #else
1762 PTHREAD_MUTEX_RECURSIVE_NP
1763 #endif
1766 PAssertPTHREAD(pthread_mutex_init, (&mutex, &attr));
1767 PAssertPTHREAD(pthread_mutexattr_destroy, (&attr));
1768 #else
1769 PAssertPTHREAD(pthread_mutex_init, (&mutex, NULL));
1770 #endif
1773 PTimedMutex::PTimedMutex(const PTimedMutex & /*mut*/)
1774 // : PSemaphore(PXMutex)
1776 #if P_HAS_RECURSIVE_MUTEX
1777 pthread_mutexattr_t attr;
1778 PAssertPTHREAD(pthread_mutexattr_init, (&attr));
1779 PAssertPTHREAD(pthread_mutexattr_settype, (&attr,
1780 #if P_HAS_RECURSIVE_MUTEX == 2
1781 PTHREAD_MUTEX_RECURSIVE
1782 #else
1783 PTHREAD_MUTEX_RECURSIVE_NP
1784 #endif
1787 PAssertPTHREAD(pthread_mutex_init, (&mutex, &attr));
1788 PAssertPTHREAD(pthread_mutexattr_destroy, (&attr));
1789 #else
1790 pthread_mutex_init(&mutex, NULL);
1791 #endif
1794 PTimedMutex::~PTimedMutex()
1796 int result = pthread_mutex_destroy(&mutex);
1797 PINDEX i = 0;
1798 while ((result == EBUSY) && (i++ < 20)) {
1799 pthread_mutex_unlock(&mutex);
1800 result = pthread_mutex_destroy(&mutex);
1802 #ifdef _DEBUG
1803 PAssert((result == 0), "Error destroying mutex");
1804 #endif
1807 void PTimedMutex::Wait()
1809 pthread_t currentThreadId = pthread_self();
1811 #if P_HAS_RECURSIVE_MUTEX == 0
1813 // if the mutex is already acquired by this thread,
1814 // then just increment the lock count
1815 if (pthread_equal(lockerId, currentThreadId)) {
1816 // Note this does not need a lock as it can only be touched by the thread
1817 // which already has the mutex locked.
1818 ++lockCount;
1819 return;
1821 #endif
1823 // acquire the lock for real
1824 PAssertPTHREAD(pthread_mutex_lock, (&mutex));
1826 #if P_HAS_RECURSIVE_MUTEX == 0
1827 PAssert((lockerId == (pthread_t)-1) && (lockCount.IsZero()),
1828 "PMutex acquired whilst locked by another thread");
1829 // Note this is protected by the mutex itself only the thread with
1830 // the lock can alter it.
1831 #endif
1833 lockerId = currentThreadId;
1837 BOOL PTimedMutex::Wait(const PTimeInterval & waitTime)
1839 // get the current thread ID
1840 pthread_t currentThreadId = pthread_self();
1842 // if waiting indefinitely, then do so
1843 if (waitTime == PMaxTimeInterval) {
1844 Wait();
1845 lockerId = currentThreadId;
1846 return TRUE;
1849 #if P_HAS_RECURSIVE_MUTEX == 0
1850 // if we already have the mutex, return immediately
1851 if (pthread_equal(lockerId, currentThreadId)) {
1852 // Note this does not need a lock as it can only be touched by the thread
1853 // which already has the mutex locked.
1854 ++lockCount;
1855 return TRUE;
1857 #endif
1859 // create absolute finish time
1860 PTime finishTime;
1861 finishTime += waitTime;
1863 #if P_PTHREADS_XPG6
1865 struct timespec absTime;
1866 absTime.tv_sec = finishTime.GetTimeInSeconds();
1867 absTime.tv_nsec = finishTime.GetMicrosecond() * 1000;
1869 if (pthread_mutex_timedlock(&mutex, &absTime) != 0)
1870 return FALSE;
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
1877 // Note this is protected by the mutex itself only the thread with
1878 // the lock can alter it.
1879 lockerId = currentThreadId;
1880 return TRUE;
1882 #else // P_PTHREADS_XPG6
1884 do {
1885 if (pthread_mutex_trylock(&mutex) == 0) {
1886 #if P_HAS_RECURSIVE_MUTEX == 0
1887 PAssert((lockerId == (pthread_t)-1) && (lockCount.IsZero()),
1888 "PMutex acquired whilst locked by another thread");
1889 #endif
1890 lockerId = currentThreadId;
1892 return TRUE;
1895 PThread::Current()->Sleep(10); // sleep for 10ms
1896 } while (PTime() < finishTime);
1898 return FALSE;
1900 #endif // P_PTHREADS_XPG6
1904 void PTimedMutex::Signal()
1906 #if P_HAS_RECURSIVE_MUTEX == 0
1907 if (!pthread_equal(lockerId, pthread_self())) {
1908 PAssertAlways("PMutex signal failed - no matching wait or signal by wrong thread");
1909 return;
1912 // if lock was recursively acquired, then decrement the counter
1913 // Note this does not need a separate lock as it can only be touched by the thread
1914 // which already has the mutex locked.
1915 if (!lockCount.IsZero()) {
1916 --lockCount;
1917 return;
1920 // otherwise mark mutex as available
1921 lockerId = (pthread_t)-1;
1923 #endif
1925 PAssertPTHREAD(pthread_mutex_unlock, (&mutex));
1929 BOOL PTimedMutex::WillBlock() const
1931 #if P_HAS_RECURSIVE_MUTEX == 0
1932 pthread_t currentThreadId = pthread_self();
1933 if (currentThreadId == lockerId)
1934 return FALSE;
1935 #endif
1937 pthread_mutex_t * mp = (pthread_mutex_t*)&mutex;
1938 if (pthread_mutex_trylock(mp) != 0)
1939 return TRUE;
1941 PAssertPTHREAD(pthread_mutex_unlock, (mp));
1942 return FALSE;
1946 PSyncPoint::PSyncPoint()
1947 : PSemaphore(PXSyncPoint)
1949 PAssertPTHREAD(pthread_mutex_init, (&mutex, NULL));
1950 PAssertPTHREAD(pthread_cond_init, (&condVar, NULL));
1951 signalCount = 0;
1954 PSyncPoint::PSyncPoint(const PSyncPoint &)
1955 : PSemaphore(PXSyncPoint)
1957 PAssertPTHREAD(pthread_mutex_init, (&mutex, NULL));
1958 PAssertPTHREAD(pthread_cond_init, (&condVar, NULL));
1959 signalCount = 0;
1962 PSyncPoint::~PSyncPoint()
1964 PAssertPTHREAD(pthread_mutex_destroy, (&mutex));
1965 PAssertPTHREAD(pthread_cond_destroy, (&condVar));
1968 void PSyncPoint::Wait()
1970 PAssertPTHREAD(pthread_mutex_lock, (&mutex));
1971 while (signalCount == 0)
1972 pthread_cond_wait(&condVar, &mutex);
1973 signalCount--;
1974 PAssertPTHREAD(pthread_mutex_unlock, (&mutex));
1978 BOOL PSyncPoint::Wait(const PTimeInterval & waitTime)
1980 PAssertPTHREAD(pthread_mutex_lock, (&mutex));
1982 PTime finishTime;
1983 finishTime += waitTime;
1984 struct timespec absTime;
1985 absTime.tv_sec = finishTime.GetTimeInSeconds();
1986 absTime.tv_nsec = finishTime.GetMicrosecond() * 1000;
1988 int err = 0;
1989 while (signalCount == 0) {
1990 err = pthread_cond_timedwait(&condVar, &mutex, &absTime);
1991 if (err == 0 || err == ETIMEDOUT)
1992 break;
1994 PAssertOS(err == EINTR && errno == EINTR);
1997 if (err == 0)
1998 signalCount--;
2000 PAssertPTHREAD(pthread_mutex_unlock, (&mutex));
2002 return err == 0;
2006 void PSyncPoint::Signal()
2008 PAssertPTHREAD(pthread_mutex_lock, (&mutex));
2009 signalCount++;
2010 PAssertPTHREAD(pthread_cond_signal, (&condVar));
2011 PAssertPTHREAD(pthread_mutex_unlock, (&mutex));
2015 BOOL PSyncPoint::WillBlock() const
2017 return signalCount == 0;