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