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.126 2004/03/24 02:37:04 csoutheren
31 * Fixed problem with incorrect usage of sem_timedwait
33 * Revision 1.125 2004/03/23 04:56:23 csoutheren
34 * Added patches to use XPG6 threading under Linux if available
35 * Thanks to Matthew Hodgson
37 * Revision 1.124 2004/02/01 11:23:16 dsandras
38 * Reverted previous Change and removed Yield call from Current (). Fix from Christian Meder <chris@onestepahead.de>. Thanks for your help, Christian!
40 * Revision 1.123 2004/01/31 13:49:18 dominance
41 * Added 2.6 performance fix as proposed by Christian Meder <chris@onestepahead.de>.
43 * Revision 1.122 2003/09/17 09:02:15 csoutheren
44 * Removed memory leak detection code
46 * Revision 1.121 2003/05/16 17:40:55 shawn
47 * On Mac OS X, thread with the highest priority should use fixed priority
48 * scheduling policy. This avoids starvation caused by desktop activity.
50 * Revision 1.120 2003/05/02 00:58:40 dereks
51 * Add test for linux at the end of PMutex::Signal. Thanks Robert!
53 * Revision 1.119 2003/05/02 00:39:11 dereks
54 * Changes to make threading work on Redhat 9
56 * Revision 1.118 2003/04/24 12:03:13 rogerh
57 * Calling pthread_mutex_unlock() on a mutex which is not locked can be
58 * considered an error. NetBSD now enforce this error so we need to quickly
59 * try locking the mutex before unlocking it in ~PThread and ~PSemaphore.
61 * Revision 1.117 2003/04/08 03:29:31 robertj
62 * Fixed IsSuspeneded() so returns TRUE if thread not started yet, this makes
63 * it the same as the Win32 semantics.
65 * Revision 1.116 2003/03/10 15:37:00 rogerh
66 * fix IsTerminated() function.
68 * Revision 1.115 2003/03/07 00:07:15 robertj
69 * Fixed Mac OS X patch which broke every other platform.
71 * Revision 1.114 2003/03/06 08:58:48 rogerh
72 * P_MACOSX now carries the OSRELEASE. Use this to enable better threads
73 * support on Darwin 6.4. Submitted by Shawn.
75 * Revision 1.113 2003/02/20 23:32:00 robertj
76 * More RTEMS support patches, thanks Sebastian Meyer.
78 * Revision 1.112 2003/01/24 10:21:06 robertj
79 * Fixed issues in RTEMS support, thanks Vladimir Nesic
81 * Revision 1.111 2003/01/20 10:13:18 rogerh
82 * NetBSD thread changes
84 * Revision 1.110 2003/01/20 10:05:46 rogerh
85 * NetBSD thread changes
87 * Revision 1.109 2003/01/08 08:47:51 rogerh
88 * Add new Sleep() function for GNU PTH threads.
89 * Taken from NetBSD's package which uses PTH.
90 * Note: I am not sure this works correctly.
92 * Revision 1.108 2003/01/06 18:49:15 rogerh
93 * Back out pthead_kill to pthread_cancel change on NetBSD
95 * Revision 1.107 2002/12/11 05:39:26 robertj
96 * Added logging for file handle changes.
97 * Fixd bug where internal maxHandles not set when increased.
99 * Revision 1.106 2002/12/02 03:57:18 robertj
100 * More RTEMS support patches, thank you Vladimir Nesic.
102 * Revision 1.105 2002/11/22 10:14:07 robertj
103 * QNX port, thanks Xiaodan Tang
105 * Revision 1.104 2002/11/04 16:01:27 rogerh
106 * Using pthread_cancel and not pthread_kill with SIGKILL to terminate a thread
107 * On FreeBSD the thread does not have a handler for SIGKILL, it passes it up
108 * to the main process which gets killed! Assume the other BSDs are the same.
110 * Revision 1.103 2002/10/24 00:40:56 robertj
111 * Put back ability to terminate a thread from that threads context (removed
112 * in revision 1.101) but requires that destructor not do so.
113 * Changed pipe close to allow for possible EINTR, and retry close.
115 * Revision 1.102 2002/10/24 00:25:13 robertj
116 * Changed high load thread problem fix from the termination function to start
117 * function to finally, once and for all (I hope!) fix the race condition.
119 * Revision 1.101 2002/10/23 14:56:22 craigs
120 * Fixed problem with pipe leak under some circumstances
122 * Revision 1.100 2002/10/23 04:29:32 robertj
123 * Improved debugging for thread create/start/stop/destroy.
124 * Fixed race condition bug if auto-delete thread starts and completes before
125 * pthread_create returns, PX_threadId is not set yet!
127 * Revision 1.99 2002/10/22 07:42:52 robertj
128 * Added extra debugging for file handle and thread leak detection.
130 * Revision 1.98 2002/10/18 03:05:39 robertj
131 * Fixed thread leak caused by fixing the thread crash a few revisions back,
132 * caused by strange pthreads behaviour, at least under Linux.
134 * Revision 1.97 2002/10/17 13:44:27 robertj
135 * Port to RTEMS, thanks Vladimir Nesic.
137 * Revision 1.96 2002/10/17 12:57:24 robertj
138 * Added ability to increase maximum file handles on a process.
140 * Revision 1.95 2002/10/16 11:26:29 rogerh
141 * Add missing include. Noticed by Matthias on the GnomeMeeting IRC
143 * Revision 1.94 2002/10/10 03:09:48 robertj
144 * Fixed high load race condition when starting threads.
146 * Revision 1.93 2002/10/05 05:22:43 robertj
147 * Fixed adding GetThreadId() function.
149 * Revision 1.92 2002/10/01 06:27:48 robertj
150 * Added bullet proofing against possible EINTR error returns on all pthread
151 * functions when under heavy load. Linux really should NOT do this, but ...
153 * Revision 1.91 2002/09/04 03:14:18 robertj
154 * Backed out changes submitted by Martin Froehlich as they do not appear to
155 * actually do anything other than add a sychronisation point. The variables
156 * the patches intended to protect were already protected.
157 * Fixed bug where if a PMutex was signalled by a thread that did not have it
158 * locked, it would assert but continue to alter PMutex variables such that
159 * a deadlock or crash is likely.
161 * Revision 1.90 2002/08/29 01:50:40 robertj
162 * Changed the pthread_create so does retries if get EINTR or EAGAIN errors
163 * which indicate a (possibly) temporary resource limit.
164 * Enabled and adjusted tracing.
166 * Revision 1.89 2002/08/22 13:05:57 craigs
167 * Fixed problems with mutex implementation thanks to Martin Froehlich
169 * Revision 1.88 2002/07/15 06:56:59 craigs
170 * Fixed missing brace
172 * Revision 1.87 2002/07/15 06:39:23 craigs
173 * Added function to allow raising of per-process file handle limit
175 * Revision 1.86 2002/06/27 06:38:58 robertj
176 * Changes to remove memory leak display for things that aren't memory leaks.
178 * Revision 1.85 2002/06/27 02:04:01 robertj
179 * Fixed NetBSD compatibility issue, thanks Motoyuki OHMORI.
181 * Revision 1.84 2002/06/04 00:25:31 robertj
182 * Fixed incorrectly initialised trace indent, thanks Artis Kugevics
184 * Revision 1.83 2002/05/21 09:13:00 robertj
185 * Fixed problem when using posix recursive mutexes, thanks Artis Kugevics
187 * Revision 1.82 2002/04/24 01:11:37 robertj
188 * Fixed problem with PTRACE_BLOCK indent level being correct across threads.
190 * Revision 1.81 2002/04/16 10:57:26 rogerh
191 * Change WaitForTermination() so it does not use 100% CPU.
192 * Reported by Andrea <ghittino@tiscali.it>
194 * Revision 1.80 2002/01/23 04:26:36 craigs
195 * Added copy constructors for PSemaphore, PMutex and PSyncPoint to allow
196 * use of default copy constructors for objects containing instances of
199 * Revision 1.79 2002/01/10 06:36:58 robertj
200 * Fixed possible resource leak under Solaris, thanks Joegen Baclor
202 * Revision 1.78 2001/12/17 11:06:46 robertj
203 * Removed assert on NULL PThread::Current(), can occur if thread from other
206 * Revision 1.77 2001/10/03 05:11:50 robertj
207 * Fixed PSyncPoint wait with timeout when have pending signals.
209 * Revision 1.76 2001/09/27 23:50:03 craigs
210 * Fixed typo in PSemaphone destructor
212 * Revision 1.75 2001/09/24 10:09:48 rogerh
213 * Fix an uninitialised variable problem.
215 * Revision 1.74 2001/09/20 05:38:25 robertj
216 * Changed PSyncPoint to use pthread cond so timed wait blocks properly.
217 * Also prevented semaphore from being created if subclass does not use it.
219 * Revision 1.73 2001/09/19 17:37:47 craigs
220 * Added support for nested mutexes under Linux
222 * Revision 1.72 2001/09/18 06:53:35 robertj
223 * Made sure suspend can't exit early if get spurious signal
225 * Revision 1.71 2001/09/18 05:56:03 robertj
226 * Fixed numerous problems with thread suspend/resume and signals handling.
228 * Revision 1.70 2001/09/10 03:03:02 robertj
229 * Major change to fix problem with error codes being corrupted in a
230 * PChannel when have simultaneous reads and writes in threads.
231 * Changed threading so does not actually start thread until Resume(), makes
232 * the logic of start up much simpler and more portable.
233 * Quite a bit of tidyin up of the pthreads code.
235 * Revision 1.69 2001/08/30 08:57:40 robertj
236 * Changed calls to usleep to be PThread::Yield(), normalising single
237 * timeslice process swap out.
239 * Revision 1.68 2001/08/20 06:55:45 robertj
240 * Fixed ability to have PMutex::Wait() with times less than one second.
241 * Fixed small error in return value of block on I/O function, not critical.
243 * Revision 1.67 2001/08/07 02:50:03 craigs
244 * Fixed potential race condition in IO blocking
246 * Revision 1.66 2001/07/09 13:23:37 rogerh
247 * Fix a subtle bug in semaphore wait which showed up on FreeBSD
249 * Revision 1.65 2001/05/29 00:49:18 robertj
250 * Added ability to put in a printf %x in thread name to get thread object
251 * address into user settable thread name.
253 * Revision 1.64 2001/05/23 00:18:55 robertj
254 * Added support for real time threads, thanks Erland Lewin.
256 * Revision 1.63 2001/04/20 09:27:25 robertj
257 * Fixed previous change for auto delete threads, must have thread ID zeroed.
259 * Revision 1.62 2001/04/20 09:09:05 craigs
260 * Removed possible race condition whilst shutting down threads
262 * Revision 1.61 2001/03/20 06:44:25 robertj
263 * Lots of changes to fix the problems with terminating threads that are I/O
264 * blocked, especially when doing orderly shutdown of service via SIGTERM.
266 * Revision 1.60 2001/03/14 01:16:11 robertj
267 * Fixed signals processing, now uses housekeeping thread to handle signals
268 * synchronously. This also fixes issues with stopping PServiceProcess.
270 * Revision 1.59 2001/02/25 19:39:42 rogerh
271 * Use a Semaphore on Mac OS X to support threads which are started as 'suspended'
273 * Revision 1.58 2001/02/24 14:49:22 rogerh
274 * Add missing bracket
276 * Revision 1.57 2001/02/24 13:29:34 rogerh
277 * Mac OS X change to avoid Assertion
279 * Revision 1.56 2001/02/24 13:24:24 rogerh
280 * Add PThread support for Mac OS X and Darwin. There is one major issue. This
281 * OS does not suport pthread_kill() and sigwait() so we cannot support the
282 * Suspend() and Resume() functions to start and stop threads and we cannot
283 * create new threads in 'suspended' mode.
284 * Calling Suspend() raises an assertion. Calling Resume() does nothing.
285 * Threads started in 'suspended' mode start immediatly.
287 * Revision 1.55 2001/02/21 22:48:42 robertj
288 * Fixed incorrect test in PSemaphore::WillBlock() just added, thank Artis Kugevics.
290 * Revision 1.54 2001/02/20 00:21:14 robertj
291 * Fixed major bug in PSemapahore::WillBlock(), thanks Tomas Heran.
293 * Revision 1.53 2000/12/21 12:36:32 craigs
294 * Removed potential to stop threads twice
296 * Revision 1.52 2000/12/05 08:24:50 craigs
297 * Fixed problem with EINTR causing havoc
299 * Revision 1.51 2000/11/16 11:06:38 rogerh
300 * Add a better fix for the "user signal 2" aborts seen on FreeBSD 4.2 and above.
301 * We need to sched_yeild() after the pthread_create() to make sure the new thread
302 * actually has a chance to execute. The abort problem was caused when the
303 * resume signal was issued before the thread was ready for it.
305 * Revision 1.50 2000/11/12 23:30:02 craigs
306 * Added extra WaitForTermination to assist bug location
308 * Revision 1.49 2000/11/12 08:16:07 rogerh
309 * This change and the previous change, make pthreads work on FreeBSD 4.2.
310 * FreeBSD has improved its thread signal handling and now correctly generates a
311 * SIGUSR2 signal on a thread (the Resume Signal). However there was no handler
312 * for this signal and applications would abort with "User signal 2".
313 * So, a dummy sigResumeHandler has been added.
315 * Revision 1.48 2000/11/12 07:57:45 rogerh
316 * *** empty log message ***
318 * Revision 1.47 2000/10/31 08:09:51 rogerh
319 * Change return type of PX_GetThreadId() to save unnecessary typecasting
321 * Revision 1.46 2000/10/31 07:52:06 rogerh
322 * Add type casts to allow the code to compile on FreeBSD 4.1.1
324 * Revision 1.45 2000/10/30 05:48:33 robertj
325 * Added assert when get nested mutex.
327 * Revision 1.44 2000/10/24 03:32:40 robertj
328 * Fixed problem where thread that uses PThread::Current() in dtor crashes.
330 * Revision 1.43 2000/10/20 06:11:48 robertj
331 * Added function to change auto delete flag on a thread.
333 * Revision 1.42 2000/09/20 04:24:09 craigs
334 * Added extra tracing, and removed segv on exit when using tracing
336 * Revision 1.41 2000/06/21 01:01:22 robertj
337 * AIX port, thanks Wolfgang Platzer (wolfgang.platzer@infonova.at).
339 * Revision 1.40 2000/04/13 07:21:10 rogerh
340 * Fix typo in #defined
342 * Revision 1.39 2000/04/11 11:38:49 rogerh
343 * More NetBSD Pthread changes
345 * Revision 1.38 2000/04/10 11:47:02 rogerh
346 * Add initial NetBSD pthreads support
348 * Revision 1.37 2000/04/06 12:19:49 rogerh
349 * Add Mac OS X support submitted by Kevin Packard
351 * Revision 1.36 2000/03/20 22:56:34 craigs
352 * Fixed problems with race conditions caused by testing or changing
353 * attributes on a terminated thread. Only occured on a fast machine!
355 * Revision 1.35 2000/03/17 03:45:40 craigs
356 * Fixed problem with connect call hanging
358 * Revision 1.34 2000/03/08 12:17:09 rogerh
359 * Add OpenBSD support
361 * Revision 1.33 2000/02/29 13:18:21 robertj
362 * Added named threads to tracing, thanks to Dave Harvey
364 * Revision 1.32 2000/01/20 08:20:57 robertj
365 * FreeBSD v3 compatibility changes, thanks Roger Hardiman & Motonori Shindo
367 * Revision 1.31 1999/11/18 14:02:57 craigs
368 * Fixed problem with houskeeping thread termination
370 * Revision 1.30 1999/11/15 01:12:56 craigs
371 * Fixed problem with PSemaphore::Wait consuming 100% CPU
373 * Revision 1.29 1999/10/30 13:44:11 craigs
374 * Added correct method of aborting socket operations asynchronously
376 * Revision 1.28 1999/10/24 13:03:30 craigs
377 * Changed to capture io break signal
379 * Revision 1.27 1999/09/23 06:52:16 robertj
380 * Changed PSemaphore to use Posix semaphores.
382 * Revision 1.26 1999/09/03 02:26:25 robertj
383 * Changes to aid in breaking I/O locks on thread termination. Still needs more work esp in BSD!
385 * Revision 1.25 1999/09/02 11:56:35 robertj
386 * Fixed problem with destroying PMutex that is already locked.
388 * Revision 1.24 1999/08/24 13:40:56 craigs
389 * Fixed problem with condwait destorys failing on linux
391 * Revision 1.23 1999/08/23 05:33:45 robertj
392 * Made last threading changes Linux only.
394 * Revision 1.22 1999/08/23 05:14:13 robertj
395 * Removed blocking of interrupt signals as does not work in Linux threads.
397 * Revision 1.21 1999/07/30 00:40:32 robertj
398 * Fixed problem with signal variable in non-Linux platforms
400 * Revision 1.20 1999/07/19 01:32:24 craigs
401 * Changed signals used in pthreads code, is used by linux version.
403 * Revision 1.19 1999/07/15 13:10:55 craigs
404 * Fixed problem with EINTR in nontimed sempahore waits
406 * Revision 1.18 1999/07/15 13:05:33 robertj
407 * Fixed problem with getting EINTR in semaphore wait, is normal, not error.
409 * Revision 1.17 1999/07/11 13:42:13 craigs
410 * pthreads support for Linux
412 * Revision 1.16 1999/05/12 03:29:20 robertj
413 * Fixed problem with semaphore free, done at wrong time.
415 * Revision 1.15 1999/04/29 08:41:26 robertj
416 * Fixed problems with uninitialised mutexes in PProcess.
418 * Revision 1.14 1999/03/16 10:54:16 robertj
419 * Added parameterless version of WaitForTermination.
421 * Revision 1.13 1999/03/16 10:30:37 robertj
422 * Added missing PThread::WaitForTermination function.
424 * Revision 1.12 1999/01/12 12:09:51 robertj
425 * Removed redundent member variable, was in common.
426 * Fixed BSD threads compatibility.
428 * Revision 1.11 1999/01/11 12:05:56 robertj
429 * Fixed some more race conditions in threads.
431 * Revision 1.10 1999/01/11 03:42:26 robertj
432 * Fixed problem with destroying thread automatically.
434 * Revision 1.9 1999/01/09 03:37:28 robertj
435 * Fixed problem with closing thread waiting on semaphore.
436 * Improved efficiency of mutex to use pthread functions directly.
438 * Revision 1.8 1999/01/08 01:31:03 robertj
439 * Support for pthreads under FreeBSD
441 * Revision 1.7 1998/12/15 12:41:07 robertj
442 * Fixed signal handling so can now ^C a pthread version.
444 * Revision 1.6 1998/11/05 09:45:04 robertj
445 * Removed StartImmediate option in thread construction.
447 * Revision 1.5 1998/09/24 04:12:25 robertj
448 * Added open software license.
452 #include <ptlib/socket.h>
453 #include <sched.h> // for sched_yield
455 #include <sys/resource.h>
458 #define SUSPEND_SIG SIGALRM
461 #define SUSPEND_SIG SIGVTALRM
465 #include <mach/mach.h>
466 #include <mach/thread_policy.h>
467 #include <sys/param.h>
468 #include <sys/sysctl.h>
469 // going to need the main thread for adjusting relative priority
470 static pthread_t baseThread
;
473 #ifdef P_HAS_SEMAPHORES_XPG6
474 #include "semaphore.h"
477 int PX_NewHandle(const char *, int);
480 #define PAssertPTHREAD(func, args) \
482 unsigned threadOpRetry = 0; \
483 while (PAssertThreadOp(func args, threadOpRetry, #func, __FILE__, __LINE__)); \
486 static BOOL
PAssertThreadOp(int retval
,
488 const char * funcname
,
493 PTRACE_IF(2, retry
> 0, "PWLib\t" << funcname
<< " required " << retry
<< " retries!");
497 if (errno
== EINTR
|| errno
== EAGAIN
) {
498 if (++retry
< 1000) {
502 usleep(10000); // Basically just swap out thread to try and clear blockage
504 return TRUE
; // Return value to try again
506 // Give up and assert
509 PAssertFunc(file
, line
, NULL
, psprintf("Function %s failed", funcname
));
514 PDECLARE_CLASS(PHouseKeepingThread
, PThread
)
516 PHouseKeepingThread()
517 : PThread(1000, NoAutoDeleteThread
, NormalPriority
, "Housekeeper")
518 { closing
= FALSE
; Resume(); }
521 void SetClosing() { closing
= TRUE
; }
528 static pthread_mutex_t MutexInitialiser
= PTHREAD_MUTEX_INITIALIZER
;
529 static pthread_cond_t CondInitialiser
= PTHREAD_COND_INITIALIZER
;
535 void PHouseKeepingThread::Main()
537 PProcess
& process
= PProcess::Current();
540 PTimeInterval delay
= process
.timers
.Process();
542 int fd
= process
.timerChangePipe
[0];
544 P_fd_set read_fds
= fd
;
545 P_timeval tval
= delay
;
546 if (::select(fd
+1, read_fds
, NULL
, NULL
, tval
) == 1) {
551 process
.PXCheckSignals();
556 void PProcess::SignalTimerChange()
558 if (housekeepingThread
== NULL
) {
559 housekeepingThread
= new PHouseKeepingThread
;
563 write(timerChangePipe
[1], &ch
, 1);
567 void PProcess::Construct()
570 // get the file descriptor limit
572 PAssertOS(getrlimit(RLIMIT_NOFILE
, &rl
) == 0);
573 maxHandles
= rl
.rlim_cur
;
574 PTRACE(4, "PWLib\tMaximum per-process file handles is " << maxHandles
);
576 ::pipe(timerChangePipe
);
578 maxHandles
= 500; // arbitrary value
579 socketpair(AF_INET
,SOCK_STREAM
,0,timerChangePipe
);
582 // initialise the housekeeping thread
583 housekeepingThread
= NULL
;
586 // records the main thread for priority adjusting
587 baseThread
= pthread_self();
594 BOOL
PProcess::SetMaxHandles(int newMax
)
597 // get the current process limit
599 PAssertOS(getrlimit(RLIMIT_NOFILE
, &rl
) == 0);
601 // set the new current limit
602 rl
.rlim_cur
= newMax
;
603 if (setrlimit(RLIMIT_NOFILE
, &rl
) == 0) {
604 PAssertOS(getrlimit(RLIMIT_NOFILE
, &rl
) == 0);
605 maxHandles
= rl
.rlim_cur
;
606 if (maxHandles
== newMax
) {
607 PTRACE(2, "PWLib\tNew maximum per-process file handles set to " << maxHandles
);
613 PTRACE(1, "PWLib\tCannot set per-process file handle limit to "
614 << newMax
<< " (is " << maxHandles
<< ") - check permissions");
619 PProcess::~PProcess()
621 // Don't wait for housekeeper to stop if Terminate() is called from it.
622 if (housekeepingThread
!= NULL
&& PThread::Current() != housekeepingThread
) {
623 housekeepingThread
->SetClosing();
625 housekeepingThread
->WaitForTermination();
626 delete housekeepingThread
;
632 //////////////////////////////////////////////////////////////////////////////
636 // see InitialiseProcessThread()
640 void PThread::InitialiseProcessThread()
644 PX_origStackSize
= 0;
645 PX_threadId
= pthread_self();
646 PX_priority
= NormalPriority
;
649 #ifndef P_HAS_SEMAPHORES
650 PX_waitingSemaphore
= NULL
;
651 PX_WaitSemMutex
= MutexInitialiser
;
654 PX_suspendMutex
= MutexInitialiser
;
657 PAssertOS(socketpair(AF_INET
,SOCK_STREAM
,0,unblockPipe
) == 0);
659 PAssertOS(::pipe(unblockPipe
) == 0);
662 ((PProcess
*)this)->activeThreads
.DisallowDeleteObjects();
663 ((PProcess
*)this)->activeThreads
.SetAt((unsigned)PX_threadId
, this);
665 traceBlockIndentLevel
= 0;
669 PThread::PThread(PINDEX stackSize
,
670 AutoDeleteFlag deletion
,
671 Priority priorityLevel
,
672 const PString
& name
)
675 autoDelete
= (deletion
== AutoDeleteThread
);
677 PAssert(stackSize
> 0, PInvalidParameter
);
678 PX_origStackSize
= stackSize
;
680 PX_priority
= priorityLevel
;
683 #ifndef P_HAS_SEMAPHORES
684 PX_waitingSemaphore
= NULL
;
685 PX_WaitSemMutex
= MutexInitialiser
;
688 PX_suspendMutex
= MutexInitialiser
;
691 PAssertOS(socketpair(AF_INET
,SOCK_STREAM
,0,unblockPipe
) == 0);
693 PAssertOS(::pipe(unblockPipe
) == 0);
695 PX_NewHandle("Thread unblock pipe", PMAX(unblockPipe
[0], unblockPipe
[1]));
697 // new thread is actually started the first time Resume() is called.
698 PX_firstTimeStart
= TRUE
;
700 traceBlockIndentLevel
= 0;
702 PTRACE(5, "PWLib\tCreated thread " << this << ' ' << threadName
);
708 if (PX_threadId
!= 0 && PX_threadId
!= pthread_self())
711 PAssertPTHREAD(::close
, (unblockPipe
[0]));
712 PAssertPTHREAD(::close
, (unblockPipe
[1]));
714 #ifndef P_HAS_SEMAPHORES
715 pthread_mutex_destroy(&PX_WaitSemMutex
);
719 // If the mutex was not locked, the unlock will fail */
720 pthread_mutex_trylock(&PX_suspendMutex
);
722 pthread_mutex_unlock(&PX_suspendMutex
);
723 pthread_mutex_destroy(&PX_suspendMutex
);
725 PTRACE(5, "PWLib\tDestroyed thread " << this << ' ' << threadName
);
729 void PThread::Restart()
734 pthread_attr_t threadAttr
;
735 pthread_attr_init(&threadAttr
);
736 pthread_attr_setdetachstate(&threadAttr
, PTHREAD_CREATE_DETACHED
);
740 Set realtime scheduling if our effective user id is root (only then is this
741 allowed) AND our priority is Highest.
742 As far as I can see, we could use either SCHED_FIFO or SCHED_RR here, it
744 I don't know if other UNIX OSs have SCHED_FIFO and SCHED_RR as well.
746 WARNING: a misbehaving thread (one that never blocks) started with Highest
747 priority can hang the entire machine. That is why root permission is
750 if ((geteuid() == 0) && (PX_priority
== HighestPriority
))
751 PAssertPTHREAD(pthread_attr_setschedpolicy
, (&threadAttr
, SCHED_FIFO
));
752 #elif defined(P_RTEMS)
753 pthread_attr_setstacksize(&threadAttr
, 2*PTHREAD_MINIMUM_STACK_SIZE
);
754 pthread_attr_setinheritsched(&threadAttr
, PTHREAD_EXPLICIT_SCHED
);
755 pthread_attr_setschedpolicy(&threadAttr
, SCHED_OTHER
);
756 struct sched_param sched_param
;
757 sched_param
.sched_priority
= 125; /* set medium priority */
758 pthread_attr_setschedparam(&threadAttr
, &sched_param
);
761 PAssertPTHREAD(pthread_create
, (&PX_threadId
, &threadAttr
, PX_ThreadStart
, this));
764 if (PX_priority
== HighestPriority
) {
765 PTRACE(1, "set thread to have the highest priority (MACOSX)");
766 SetPriority(HighestPriority
);
772 void PX_SuspendSignalHandler(int)
774 PThread
* thread
= PThread::Current();
778 BOOL notResumed
= TRUE
;
781 notResumed
= ::read(thread
->unblockPipe
[0], &ch
, 1) < 0 && errno
== EINTR
;
782 #if !( defined(P_NETBSD) && defined(P_NO_CANCEL) )
783 pthread_testcancel();
789 void PThread::Suspend(BOOL susp
)
791 PAssertPTHREAD(pthread_mutex_lock
, (&PX_suspendMutex
));
793 // Check for start up condition, first time Resume() is called
794 if (PX_firstTimeStart
) {
798 if (PX_suspendCount
> 0)
800 if (PX_suspendCount
== 0) {
801 PX_firstTimeStart
= FALSE
;
806 PAssertPTHREAD(pthread_mutex_unlock
, (&PX_suspendMutex
));
810 #if defined(P_MACOSX) && (P_MACOSX <= 55)
811 // Suspend - warn the user with an Assertion
812 PAssertAlways("Cannot suspend threads on Mac OS X due to lack of pthread_kill()");
814 if (pthread_kill(PX_threadId
, 0) == 0) {
816 // if suspending, then see if already suspended
819 if (PX_suspendCount
== 1) {
820 if (PX_threadId
!= pthread_self()) {
821 signal(SUSPEND_SIG
, PX_SuspendSignalHandler
);
822 pthread_kill(PX_threadId
, SUSPEND_SIG
);
825 PAssertPTHREAD(pthread_mutex_unlock
, (&PX_suspendMutex
));
826 PX_SuspendSignalHandler(SUSPEND_SIG
);
827 return; // Mutex already unlocked
832 // if resuming, then see if to really resume
833 else if (PX_suspendCount
> 0) {
835 if (PX_suspendCount
== 0)
840 PAssertPTHREAD(pthread_mutex_unlock
, (&PX_suspendMutex
));
845 void PThread::Resume()
851 BOOL
PThread::IsSuspended() const
853 if (PX_firstTimeStart
)
859 PAssertPTHREAD(pthread_mutex_lock
, ((pthread_mutex_t
*)&PX_suspendMutex
));
860 BOOL suspended
= PX_suspendCount
!= 0;
861 PAssertPTHREAD(pthread_mutex_unlock
, ((pthread_mutex_t
*)&PX_suspendMutex
));
866 void PThread::SetAutoDelete(AutoDeleteFlag deletion
)
868 PAssert(deletion
!= AutoDeleteThread
|| this != &PProcess::Current(), PLogicError
);
869 autoDelete
= deletion
== AutoDeleteThread
;
873 // obtain thread priority of the main thread
875 GetThreadBasePriority ()
877 thread_basic_info_data_t threadInfo
;
878 policy_info_data_t thePolicyInfo
;
881 if (baseThread
== 0) {
886 count
= THREAD_BASIC_INFO_COUNT
;
887 thread_info (pthread_mach_thread_np (baseThread
), THREAD_BASIC_INFO
,
888 (integer_t
*)&threadInfo
, &count
);
890 switch (threadInfo
.policy
) {
891 case POLICY_TIMESHARE
:
892 count
= POLICY_TIMESHARE_INFO_COUNT
;
893 thread_info(pthread_mach_thread_np (baseThread
),
894 THREAD_SCHED_TIMESHARE_INFO
,
895 (integer_t
*)&(thePolicyInfo
.ts
), &count
);
896 return thePolicyInfo
.ts
.base_priority
;
900 count
= POLICY_FIFO_INFO_COUNT
;
901 thread_info(pthread_mach_thread_np (baseThread
),
902 THREAD_SCHED_FIFO_INFO
,
903 (integer_t
*)&(thePolicyInfo
.fifo
), &count
);
904 if (thePolicyInfo
.fifo
.depressed
) {
905 return thePolicyInfo
.fifo
.depress_priority
;
907 return thePolicyInfo
.fifo
.base_priority
;
912 count
= POLICY_RR_INFO_COUNT
;
913 thread_info(pthread_mach_thread_np (baseThread
),
914 THREAD_SCHED_RR_INFO
,
915 (integer_t
*)&(thePolicyInfo
.rr
), &count
);
916 if (thePolicyInfo
.rr
.depressed
) {
917 return thePolicyInfo
.rr
.depress_priority
;
919 return thePolicyInfo
.rr
.base_priority
;
928 void PThread::SetPriority(Priority priorityLevel
)
930 PX_priority
= priorityLevel
;
936 struct sched_param sched_param
;
938 if ((priorityLevel
== HighestPriority
) && (geteuid() == 0) ) {
939 sched_param
.sched_priority
= sched_get_priority_min( SCHED_FIFO
);
941 PAssertPTHREAD(pthread_setschedparam
, (PX_threadId
, SCHED_FIFO
, &sched_param
));
943 else if (priorityLevel
!= HighestPriority
) {
944 /* priority 0 is the only permitted value for the SCHED_OTHER scheduler */
945 sched_param
.sched_priority
= 0;
947 PAssertPTHREAD(pthread_setschedparam
, (PX_threadId
, SCHED_OTHER
, &sched_param
));
951 #if defined(P_MACOSX)
955 if (priorityLevel
== HighestPriority
) {
956 /* get fixed priority */
960 thread_extended_policy_data_t theFixedPolicy
;
961 thread_precedence_policy_data_t thePrecedencePolicy
;
962 long relativePriority
;
964 theFixedPolicy
.timeshare
= false; // set to true for a non-fixed thread
965 result
= thread_policy_set (pthread_mach_thread_np(PX_threadId
),
966 THREAD_EXTENDED_POLICY
,
967 (thread_policy_t
)&theFixedPolicy
,
968 THREAD_EXTENDED_POLICY_COUNT
);
969 if (result
!= KERN_SUCCESS
) {
970 PTRACE(1, "thread_policy - Couldn't set thread as fixed priority.");
975 // precedency policy's "importance" value is relative to
976 // spawning thread's priority
978 relativePriority
= 62 - GetThreadBasePriority();
979 PTRACE(1, "relativePriority is " << relativePriority
<<
980 " base priority is " << GetThreadBasePriority());
982 thePrecedencePolicy
.importance
= relativePriority
;
983 result
= thread_policy_set (pthread_mach_thread_np(PX_threadId
),
984 THREAD_PRECEDENCE_POLICY
,
985 (thread_policy_t
)&thePrecedencePolicy
,
986 THREAD_PRECEDENCE_POLICY_COUNT
);
987 if (result
!= KERN_SUCCESS
) {
988 PTRACE(1, "thread_policy - Couldn't set thread priority.");
996 PThread::Priority
PThread::GetPriority() const
999 int schedulingPolicy
;
1000 struct sched_param schedParams
;
1002 PAssertPTHREAD(pthread_getschedparam
, (PX_threadId
, &schedulingPolicy
, &schedParams
));
1004 switch( schedulingPolicy
)
1011 return HighestPriority
;
1014 /* Unknown scheduler. We don't know what priority this thread has. */
1015 PTRACE(1, "PWLib\tPThread::GetPriority: unknown scheduling policy #" << schedulingPolicy
);
1019 return NormalPriority
; /* as good a guess as any */
1023 #ifndef P_HAS_SEMAPHORES
1024 void PThread::PXSetWaitingSemaphore(PSemaphore
* sem
)
1026 PAssertPTHREAD(pthread_mutex_lock
, (&PX_WaitSemMutex
));
1027 PX_waitingSemaphore
= sem
;
1028 PAssertPTHREAD(pthread_mutex_unlock
, (&PX_WaitSemMutex
));
1034 // GNU PTH threads version (used by NetBSD)
1035 // Taken from NetBSD pkg patches
1036 void PThread::Sleep(const PTimeInterval
& timeout
)
1039 PTime targetTime
= PTime() + timeout
;
1044 while (lastTime
< targetTime
) {
1045 P_timeval tval
= targetTime
- lastTime
;
1046 if (select(0, NULL
, NULL
, NULL
, tval
) < 0 && errno
!= EINTR
)
1049 pthread_testcancel();
1056 // Normal Posix threads version
1057 void PThread::Sleep(const PTimeInterval
& timeout
)
1060 PTime targetTime
= lastTime
+ timeout
;
1062 P_timeval tval
= targetTime
- lastTime
;
1063 if (select(0, NULL
, NULL
, NULL
, tval
) < 0 && errno
!= EINTR
)
1066 #if !( defined(P_NETBSD) && defined(P_NO_CANCEL) )
1067 pthread_testcancel();
1071 } while (lastTime
< targetTime
);
1075 void PThread::Yield()
1081 PThread
* PThread::Current()
1083 PProcess
& process
= PProcess::Current();
1084 process
.threadMutex
.Wait();
1085 PThread
* thread
= process
.activeThreads
.GetAt((unsigned)pthread_self());
1086 process
.threadMutex
.Signal();
1091 void PThread::Terminate()
1093 if (PX_origStackSize
<= 0)
1096 // don't use PThread::Current, as the thread may already not be in the
1097 // active threads list
1098 if (PX_threadId
== pthread_self()) {
1106 PTRACE(2, "PWLib\tForcing termination of thread " << (void *)this);
1109 WaitForTermination(20);
1111 #ifndef P_HAS_SEMAPHORES
1112 PAssertPTHREAD(pthread_mutex_lock
, (&PX_WaitSemMutex
));
1113 if (PX_waitingSemaphore
!= NULL
) {
1114 PAssertPTHREAD(pthread_mutex_lock
, (&PX_waitingSemaphore
->mutex
));
1115 PX_waitingSemaphore
->queuedLocks
--;
1116 PAssertPTHREAD(pthread_mutex_unlock
, (&PX_waitingSemaphore
->mutex
));
1117 PX_waitingSemaphore
= NULL
;
1119 PAssertPTHREAD(pthread_mutex_unlock
, (&PX_WaitSemMutex
));
1122 #if ( defined(P_NETBSD) && defined(P_NO_CANCEL) )
1123 pthread_kill(PX_threadId
,SIGKILL
);
1126 pthread_cancel(PX_threadId
);
1132 BOOL
PThread::IsTerminated() const
1134 if (PX_threadId
== 0)
1137 #if defined(P_MACOSX) && (P_MACOSX <= 55)
1138 // MacOS X (darwin 5.5) does not support pthread_kill so we cannot use it
1139 // to test the validity of the thread
1141 if (pthread_kill(PX_threadId
, 0) != 0)
1145 PTRACE(7, "PWLib\tIsTerminated(" << (void *)this << ") not dead yet");
1150 void PThread::WaitForTermination() const
1152 PAssert(Current() != this, "Waiting for self termination!");
1154 while (!IsTerminated()) {
1155 Sleep(10); // sleep for 10ms. This slows down the busy loop removing 100%
1156 // CPU usage and also yeilds so other threads can run.
1161 BOOL
PThread::WaitForTermination(const PTimeInterval
& maxWait
) const
1163 PAssert(Current() != this, "Waiting for self termination!");
1165 PTRACE(6, "PWLib\tWaitForTermination(" << maxWait
<< ')');
1167 PTimer timeout
= maxWait
;
1168 while (!IsTerminated()) {
1171 Sleep(10); // sleep for 10ms. This slows down the busy loop removing 100%
1172 // CPU usage and also yeilds so other threads can run.
1178 void * PThread::PX_ThreadStart(void * arg
)
1180 pthread_t threadId
= pthread_self();
1183 pthread_detach(threadId
);
1185 PThread
* thread
= (PThread
*)arg
;
1187 // Added this to guarantee that the thread creation (PThread::Restart)
1188 // has completed before we start the thread. Then the PX_threadId has
1190 pthread_mutex_lock(&thread
->PX_suspendMutex
);
1192 thread
->SetThreadName(thread
->GetThreadName());
1194 pthread_mutex_unlock(&thread
->PX_suspendMutex
);
1196 PProcess
& process
= PProcess::Current();
1198 PINDEX newHighWaterMark
= 0;
1199 static PINDEX highWaterMark
= 0;
1201 // add thread to thread list
1202 process
.threadMutex
.Wait();
1203 process
.activeThreads
.SetAt((unsigned)threadId
, thread
);
1204 if (process
.activeThreads
.GetSize() > highWaterMark
)
1205 newHighWaterMark
= highWaterMark
= process
.activeThreads
.GetSize();
1206 process
.threadMutex
.Signal();
1208 PTRACE_IF(4, newHighWaterMark
> 0, "PWLib\tThread high water mark set: " << newHighWaterMark
);
1210 // make sure the cleanup routine is called when the thread exits
1211 pthread_cleanup_push(PThread::PX_ThreadEnd
, arg
);
1213 PTRACE(5, "PWLib\tStarted thread " << thread
<< ' ' << thread
->threadName
);
1215 // now call the the thread main routine
1218 // execute the cleanup routine
1219 pthread_cleanup_pop(1);
1225 void PThread::PX_ThreadEnd(void * arg
)
1227 PThread
* thread
= (PThread
*)arg
;
1228 pthread_t id
= thread
->GetThreadId();
1230 // Don't know why, but pthreads under Linux at least can call this function
1231 // multiple times! Probably a bug, but we have to allow for it.
1232 PTRACE(2, "PWLib\tAttempted to multiply end thread " << thread
<< " ThreadID=" << (void *)id
);
1236 PTRACE(5, "PWLib\tEnded thread " << thread
<< ' ' << thread
->threadName
);
1238 // remove this thread from the active thread list
1239 PProcess
& process
= PProcess::Current();
1240 process
.threadMutex
.Wait();
1241 process
.activeThreads
.SetAt((unsigned)id
, NULL
);
1242 process
.threadMutex
.Signal();
1244 // delete the thread if required, note this is done this way to avoid
1245 // a race condition, the thread ID cannot be zeroed before the if!
1246 if (thread
->autoDelete
) {
1247 thread
->PX_threadId
= 0; // Prevent terminating terminated thread
1249 // Now should be safe to delete the thread!
1253 thread
->PX_threadId
= 0;
1257 int PThread::PXBlockOnIO(int handle
, int type
, const PTimeInterval
& timeout
)
1259 PTRACE(7, "PWLib\tPThread::PXBlockOnIO(" << handle
<< ',' << type
<< ')');
1261 if ((handle
< 0) || (handle
>= PProcess::Current().GetMaxHandles())) {
1262 PTRACE(2, "PWLib\tAttempt to use illegal handle in PThread::PXBlockOnIO, handle=" << handle
);
1267 // make sure we flush the buffer before doing a write
1270 P_fd_set exception_fds
;
1275 case PChannel::PXReadBlock
:
1276 case PChannel::PXAcceptBlock
:
1279 exception_fds
.Zero();
1281 case PChannel::PXWriteBlock
:
1284 exception_fds
.Zero();
1286 case PChannel::PXConnectBlock
:
1289 exception_fds
= handle
;
1292 PAssertAlways(PLogicError
);
1296 // include the termination pipe into all blocking I/O functions
1297 read_fds
+= unblockPipe
[0];
1299 P_timeval tval
= timeout
;
1300 retval
= ::select(PMAX(handle
, unblockPipe
[0])+1,
1301 read_fds
, write_fds
, exception_fds
, tval
);
1302 } while (retval
< 0 && errno
== EINTR
);
1304 if ((retval
== 1) && read_fds
.IsPresent(unblockPipe
[0])) {
1306 ::read(unblockPipe
[0], &ch
, 1);
1309 PTRACE(6, "PWLib\tUnblocked I/O");
1315 void PThread::PXAbortBlock() const
1318 ::write(unblockPipe
[1], &ch
, 1);
1322 ///////////////////////////////////////////////////////////////////////////////
1324 PSemaphore::PSemaphore(PXClass pxc
)
1327 mutex
= MutexInitialiser
;
1328 condVar
= CondInitialiser
;
1330 // these should never be used, as this constructor is
1331 // only used for PMutex and PSyncPoint and they have their
1332 // own copy constructors
1333 initialVar
= maxCountVar
= 0;
1337 PSemaphore::PSemaphore(unsigned initial
, unsigned maxCount
)
1339 pxClass
= PXSemaphore
;
1340 mutex
= MutexInitialiser
;
1341 condVar
= CondInitialiser
;
1343 initialVar
= initial
;
1344 maxCountVar
= maxCount
;
1346 #ifdef P_HAS_SEMAPHORES
1347 PAssertPTHREAD(sem_init
, (&semId
, 0, initial
));
1349 PAssert(maxCount
> 0, "Invalid semaphore maximum.");
1350 if (initial
> maxCount
)
1353 currentCount
= initial
;
1354 maximumCount
= maxCount
;
1359 PSemaphore::PSemaphore(const PSemaphore
& sem
)
1361 pxClass
= sem
.GetSemClass();
1362 mutex
= MutexInitialiser
;
1363 condVar
= CondInitialiser
;
1365 initialVar
= sem
.GetInitial();
1366 maxCountVar
= sem
.GetMaxCount();
1368 #ifdef P_HAS_SEMAPHORES
1369 PAssertPTHREAD(sem_init
, (&semId
, 0, initialVar
));
1371 PAssert(maxCountVar
> 0, "Invalid semaphore maximum.");
1372 if (initialVar
> maxCountVar
)
1373 initialVar
= maxCountVar
;
1375 currentCount
= initialVar
;
1376 maximumCount
= maxCountVar
;
1381 PSemaphore::~PSemaphore()
1383 pthread_cond_destroy(&condVar
);
1386 // If the mutex was not locked, the unlock will fail */
1387 pthread_mutex_trylock(&mutex
);
1390 pthread_mutex_unlock(&mutex
);
1391 pthread_mutex_destroy(&mutex
);
1393 if (pxClass
== PXSemaphore
) {
1394 #ifdef P_HAS_SEMAPHORES
1395 PAssertPTHREAD(sem_destroy
, (&semId
));
1397 PAssert(queuedLocks
== 0, "Semaphore destroyed with queued locks");
1403 void PSemaphore::Wait()
1405 #ifdef P_HAS_SEMAPHORES
1406 PAssertPTHREAD(sem_wait
, (&semId
));
1408 PAssertPTHREAD(pthread_mutex_lock
, (&mutex
));
1411 PThread::Current()->PXSetWaitingSemaphore(this);
1413 while (currentCount
== 0) {
1414 int err
= pthread_cond_wait(&condVar
, &mutex
);
1415 PAssert(err
== 0 || err
== EINTR
, psprintf("wait error = %i", err
));
1418 PThread::Current()->PXSetWaitingSemaphore(NULL
);
1423 PAssertPTHREAD(pthread_mutex_unlock
, (&mutex
));
1428 BOOL
PSemaphore::Wait(const PTimeInterval
& waitTime
)
1430 if (waitTime
== PMaxTimeInterval
) {
1435 // create absolute finish time
1437 finishTime
+= waitTime
;
1439 #ifdef P_HAS_SEMAPHORES
1440 #ifdef P_HAS_SEMAPHORES_XPG6
1441 // use proper timed spinlocks if supported.
1442 // http://www.opengroup.org/onlinepubs/007904975/functions/sem_timedwait.html
1444 struct timespec absTime
;
1445 absTime
.tv_sec
= finishTime
.GetTimeInSeconds();
1446 absTime
.tv_nsec
= finishTime
.GetMicrosecond() * 1000;
1448 if (sem_timedwait(&semId
, &absTime
) == 0) {
1456 // loop until timeout, or semaphore becomes available
1457 // don't use a PTimer, as this causes the housekeeping
1458 // thread to get very busy
1460 if (sem_trywait(&semId
) == 0)
1463 #if defined(P_LINUX)
1464 // sched_yield in a tight loop is bad karma
1465 // for the linux scheduler: http://www.ussg.iu.edu/hypermail/linux/kernel/0312.2/1127.html
1466 PThread::Current()->Sleep(10);
1470 } while (PTime() < finishTime
);
1477 struct timespec absTime
;
1478 absTime
.tv_sec
= finishTime
.GetTimeInSeconds();
1479 absTime
.tv_nsec
= finishTime
.GetMicrosecond() * 1000;
1481 PAssertPTHREAD(pthread_mutex_lock
, (&mutex
));
1483 PThread
* thread
= PThread::Current();
1484 thread
->PXSetWaitingSemaphore(this);
1488 while (currentCount
== 0) {
1489 int err
= pthread_cond_timedwait(&condVar
, &mutex
, &absTime
);
1490 if (err
== ETIMEDOUT
) {
1495 PAssert(err
== 0 || err
== EINTR
, psprintf("timed wait error = %i", err
));
1498 thread
->PXSetWaitingSemaphore(NULL
);
1504 PAssertPTHREAD(pthread_mutex_unlock
, ((pthread_mutex_t
*)&mutex
));
1511 void PSemaphore::Signal()
1513 #ifdef P_HAS_SEMAPHORES
1514 PAssertPTHREAD(sem_post
, (&semId
));
1516 PAssertPTHREAD(pthread_mutex_lock
, (&mutex
));
1518 if (currentCount
< maximumCount
)
1521 if (queuedLocks
> 0)
1522 PAssertPTHREAD(pthread_cond_signal
, (&condVar
));
1524 PAssertPTHREAD(pthread_mutex_unlock
, (&mutex
));
1529 BOOL
PSemaphore::WillBlock() const
1531 #ifdef P_HAS_SEMAPHORES
1532 if (sem_trywait((sem_t
*)&semId
) != 0) {
1533 PAssertOS(errno
== EAGAIN
|| errno
== EINTR
);
1536 PAssertPTHREAD(sem_post
, ((sem_t
*)&semId
));
1539 return currentCount
== 0;
1543 #if defined(P_QNX) && defined(P_HAS_RECURSIVE_MUTEX)
1544 #define PTHREAD_MUTEX_RECURSIVE_NP PTHREAD_MUTEX_RECURSIVE
1548 : PSemaphore(PXMutex
)
1550 #ifdef P_HAS_RECURSIVE_MUTEX
1551 pthread_mutexattr_t attr
;
1552 pthread_mutexattr_init(&attr
);
1553 pthread_mutexattr_settype(&attr
, PTHREAD_MUTEX_RECURSIVE_NP
);
1554 pthread_mutex_init(&mutex
, &attr
);
1556 ownerThreadId
= (pthread_t
)-1;
1561 PMutex::PMutex(const PMutex
& /*mut*/)
1562 : PSemaphore(PXMutex
)
1564 #ifdef P_HAS_RECURSIVE_MUTEX
1565 pthread_mutexattr_t attr
;
1566 pthread_mutexattr_init(&attr
);
1567 pthread_mutexattr_settype(&attr
, PTHREAD_MUTEX_RECURSIVE_NP
);
1568 pthread_mutex_init(&mutex
, &attr
);
1570 ownerThreadId
= (pthread_t
)-1;
1577 #ifndef P_HAS_RECURSIVE_MUTEX
1578 pthread_t currentThreadId
= pthread_self();
1580 // if the mutex is already acquired by this thread,
1581 // then just increment the lock count
1582 if (pthread_equal(ownerThreadId
, currentThreadId
)) {
1583 // Note this does not need a lock as it can only be touched by the thread
1584 // which already has the mutex locked.
1590 // acquire the lock for real
1591 PAssertPTHREAD(pthread_mutex_lock
, (&mutex
));
1593 #ifndef P_HAS_RECURSIVE_MUTEX
1594 PAssert((ownerThreadId
== (pthread_t
)-1) && (lockCount
== 0),
1595 "PMutex acquired whilst locked by another thread");
1596 // Note this is protected by the mutex itself only the thread with
1597 // the lock can alter it.
1598 ownerThreadId
= currentThreadId
;
1603 BOOL
PMutex::Wait(const PTimeInterval
& waitTime
)
1605 // if waiting indefinitely, then do so
1606 if (waitTime
== PMaxTimeInterval
) {
1611 #ifndef P_HAS_RECURSIVE_MUTEX
1612 // get the current thread ID
1613 pthread_t currentThreadId
= pthread_self();
1615 // if we already have the mutex, return immediately
1616 if (pthread_equal(ownerThreadId
, currentThreadId
)) {
1617 // Note this does not need a lock as it can only be touched by the thread
1618 // which already has the mutex locked.
1624 // create absolute finish time
1626 finishTime
+= waitTime
;
1629 if (pthread_mutex_trylock(&mutex
) == 0) {
1630 #ifndef P_HAS_RECURSIVE_MUTEX
1631 PAssert((ownerThreadId
== (pthread_t
)-1) && (lockCount
== 0),
1632 "PMutex acquired whilst locked by another thread");
1633 // Note this is protected by the mutex itself only the thread with
1634 // the lock can alter it.
1635 ownerThreadId
= currentThreadId
;
1641 PThread::Current()->Sleep(10); // sleep for 10ms
1642 } while (PTime() < finishTime
);
1648 void PMutex::Signal()
1650 #ifndef P_HAS_RECURSIVE_MUTEX
1651 if (!pthread_equal(ownerThreadId
, pthread_self())) {
1652 PAssertAlways("PMutex signal failed - no matching wait or signal by wrong thread");
1656 // if lock was recursively acquired, then decrement the counter
1657 // Note this does not need a separate lock as it can only be touched by the thread
1658 // which already has the mutex locked.
1659 if (lockCount
> 0) {
1664 // otherwise mark mutex as available
1665 ownerThreadId
= (pthread_t
)-1;
1668 PAssertPTHREAD(pthread_mutex_unlock
, (&mutex
));
1672 BOOL
PMutex::WillBlock() const
1674 #ifndef P_HAS_RECURSIVE_MUTEX
1675 pthread_t currentThreadId
= pthread_self();
1676 if (currentThreadId
== ownerThreadId
)
1680 pthread_mutex_t
* mp
= (pthread_mutex_t
*)&mutex
;
1681 if (pthread_mutex_trylock(mp
) != 0)
1684 PAssertPTHREAD(pthread_mutex_unlock
, (mp
));
1689 PSyncPoint::PSyncPoint()
1690 : PSemaphore(PXSyncPoint
)
1695 PSyncPoint::PSyncPoint(const PSyncPoint
&)
1696 : PSemaphore(PXSyncPoint
)
1701 void PSyncPoint::Wait()
1703 PAssertPTHREAD(pthread_mutex_lock
, (&mutex
));
1704 while (signalCount
== 0)
1705 pthread_cond_wait(&condVar
, &mutex
);
1707 PAssertPTHREAD(pthread_mutex_unlock
, (&mutex
));
1711 BOOL
PSyncPoint::Wait(const PTimeInterval
& waitTime
)
1713 PAssertPTHREAD(pthread_mutex_lock
, (&mutex
));
1716 finishTime
+= waitTime
;
1717 struct timespec absTime
;
1718 absTime
.tv_sec
= finishTime
.GetTimeInSeconds();
1719 absTime
.tv_nsec
= finishTime
.GetMicrosecond() * 1000;
1722 while (signalCount
== 0) {
1723 err
= pthread_cond_timedwait(&condVar
, &mutex
, &absTime
);
1724 if (err
== 0 || err
== ETIMEDOUT
)
1727 PAssertOS(err
== EINTR
&& errno
== EINTR
);
1733 PAssertPTHREAD(pthread_mutex_unlock
, (&mutex
));
1739 void PSyncPoint::Signal()
1741 PAssertPTHREAD(pthread_mutex_lock
, (&mutex
));
1743 PAssertPTHREAD(pthread_cond_signal
, (&condVar
));
1744 PAssertPTHREAD(pthread_mutex_unlock
, (&mutex
));
1748 BOOL
PSyncPoint::WillBlock() const
1750 return signalCount
== 0;