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