Added a parameter to semaphore constructor to avoid ambiguity
[pwlib.git] / src / ptlib / unix / tlibbe.cxx
blobb866c35751deb3784a8cc3e60492b693d1b7274a
1 /*
2 * tlibbe.cxx
4 * Thread library implementation for BeOS
6 * Portable Windows Library
8 * The contents of this file are subject to the Mozilla Public License
9 * Version 1.0 (the "License"); you may not use this file except in
10 * compliance with the License. You may obtain a copy of the License at
11 * http://www.mozilla.org/MPL/
13 * Software distributed under the License is distributed on an "AS IS"
14 * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
15 * the License for the specific language governing rights and limitations
16 * under the License.
18 * The Original Code is Portable Windows Library.
20 * The Initial Developer of the Original Code is Equivalence Pty. Ltd.
22 * Portions are Copyright (c) 1993-1998 Equivalence Pty. Ltd.
24 * Portions are Copyright (C) 1993 Free Software Foundation, Inc.
25 * All Rights Reserved.
27 * Contributor(s): Yuri Kiryanov, ykiryanov at users.sourceforge.net
29 * $Log$
30 * Revision 1.17 2004/02/23 18:10:39 ykiryanov
31 * Added a parameter to semaphore constructor to avoid ambiguity
33 * Revision 1.16 2004/02/23 00:02:20 ykiryanov
34 * Changed my e-mail to ykiryanov at users.sourceforge.net. Just in case someone wants to collaborate
36 * Revision 1.15 2004/02/22 23:59:28 ykiryanov
37 * Added missing functions: PProcess::SetMaxHandles(), PThread::GetCurrentThreadId(),
38 * PThread::PXAbortBlock(), PSyncPoint::Signal(), ::Wait(), ::Wait(timeout), ::WillBlock()
40 * Revision 1.14 2004/02/22 04:35:04 ykiryanov
41 * Removed PMutex desctructor
43 * Revision 1.13 2003/02/26 01:13:18 robertj
44 * Fixed race condition where thread can terminatebefore an IsSuspeded() call
45 * occurs and cause an assert, thanks Sebastian Meyer
47 * Revision 1.12 2001/06/30 06:59:07 yurik
48 * Jac Goudsmit from Be submit these changes 6/28. Implemented by Yuri Kiryanov
50 * Revision 1.11 2001/03/07 06:57:32 yurik
51 * Changed email to current one
53 * Revision 1.10 2001/01/16 12:32:06 rogerh
54 * Remove duplicate SetAutoDelete() function. Submitted by
55 * Jac Goudsmit <jac_goudsmit@yahoo.com>
60 class PProcess;
61 class PSemaphore;
63 #include <ptlib.h>
65 ///////////////////////////////////////////////////////////////////////////////
66 // Threads
67 //#define DEBUG_THREADS
69 static int const priorities[] = {
70 1, // Lowest priority is 1. 0 is not
71 B_LOW_PRIORITY,
72 B_NORMAL_PRIORITY,
73 B_DISPLAY_PRIORITY,
74 B_URGENT_DISPLAY_PRIORITY,
77 int32 PThread::ThreadFunction(void * threadPtr)
79 PThread * thread = (PThread *)PAssertNULL(threadPtr);
81 PProcess & process = PProcess::Current();
83 process.activeThreadMutex.Wait();
84 process.activeThreads.SetAt(thread->threadId, thread);
85 process.activeThreadMutex.Signal();
87 process.SignalTimerChange();
89 thread->Main();
91 return 0;
94 PThread::PThread()
95 : threadId(B_BAD_THREAD_ID),
96 priority(B_NORMAL_PRIORITY),
97 originalStackSize(0)
101 PThread::PThread(PINDEX stackSize,
102 AutoDeleteFlag deletion,
103 Priority priorityLevel,
104 const PString & name)
105 : threadName(name)
107 PAssert(stackSize > 0, PInvalidParameter);
108 autoDelete = deletion == AutoDeleteThread;
109 originalStackSize = stackSize;
111 priority = priorities[priorityLevel];
113 PString str("PWLT ");
114 str += threadName;
115 #ifdef DEBUG_THREADS
116 PError << "::spawn_thread(" << str << "), priority:" << priority << endl;
117 #endif
119 threadId = ::spawn_thread(ThreadFunction, // Function
120 (const char*) str, // Name
121 priority, // Priority
122 (void *) this); // Pass this as cookie
124 PAssertOS(threadId >= B_NO_ERROR);
126 #ifdef DEBUG_THREADS
127 PError << ", id: " << threadId << endl;
128 #endif
130 if (autoDelete) {
131 PProcess & process = PProcess::Current();
132 process.deleteThreadMutex.Wait();
133 process.autoDeleteThreads.Append(this);
134 process.deleteThreadMutex.Signal();
139 PThread::~PThread()
141 if (originalStackSize <= 0)
142 return;
144 PProcess & process = PProcess::Current();
145 process.activeThreadMutex.Wait();
146 process.activeThreads.SetAt(threadId, NULL);
147 process.activeThreadMutex.Signal();
149 if (!IsTerminated())
150 Terminate();
154 void PThread::Restart()
156 PAssert(IsTerminated(), "Cannot restart running thread");
158 PString str("PWLT");
159 str += threadName;
160 #ifdef DEBUG_THREADS
161 PError << "::spawn_thread(" << str << "), priority:" << priority << endl;
162 #endif
164 threadId = ::spawn_thread(ThreadFunction, // Function
165 (const char*) str, // Name
166 priority,
167 (void *) this); // Pass this as cookie
169 #ifdef DEBUG_THREADS
170 PError << ", id: " << threadId << endl;
171 #endif
173 PAssertOS(threadId >= B_NO_ERROR);
177 void PThread::Terminate()
179 PAssert(!IsTerminated(), "Operation on terminated thread");
180 PAssert(originalStackSize > 0, PLogicError);
182 if (Current() == this)
184 sem_id semId = ::create_sem( 1, "PWST" );
185 if ( ::acquire_sem(semId) == B_NO_ERROR )
187 // Invalidate the thread
188 threadId = B_BAD_THREAD_ID;
189 ::release_sem(semId);
190 ::delete_sem(semId);
192 #ifdef DEBUG_THREADS
193 PError << "::exit_thread(0), id:" << threadId << endl;
194 #endif
195 ::exit_thread(0);
198 else
200 sem_id semId = ::create_sem( 1, "PWTS" );
201 if ( ::acquire_sem(semId) == B_NO_ERROR )
203 thread_id idToKill;
204 idToKill = threadId;
206 // Invalidate the thread
207 threadId = B_BAD_THREAD_ID;
209 // Kill it
210 if (idToKill != B_BAD_THREAD_ID)
212 ::release_sem(semId);
213 ::delete_sem(semId);
215 #ifdef DEBUG_THREADS
216 PError << "::kill_thread(" << idToKill << ")" << endl;
217 #endif
218 ::kill_thread(idToKill);
223 PAssert(threadId == B_BAD_THREAD_ID, "Can't acquire semaphore to terminate thread");
227 BOOL PThread::IsTerminated() const
229 return threadId == B_BAD_THREAD_ID;
233 void PThread::WaitForTermination() const
235 WaitForTermination(PMaxTimeInterval);
239 BOOL PThread::WaitForTermination(const PTimeInterval & /*maxWait*/) const // Fix timeout
241 status_t result = B_NO_ERROR;
242 status_t exit_value = B_NO_ERROR;
244 #ifdef DEBUG_THREADS
245 PError << "::wait_for_thread(" << threadId << "), result:";
246 #endif
248 result = ::wait_for_thread(threadId, &exit_value);
249 if ( result == B_INTERRUPTED ) { // thread was killed.
250 #ifdef DEBUG_THREADS
251 PError << "B_INTERRUPTED" << endl;
252 #endif
253 return TRUE;
256 if ( result == B_OK ) { // thread is dead
257 #ifdef DEBUG_THREADS
258 PError << "B_OK" << endl;
259 #endif
260 return TRUE;
263 if ( result == B_BAD_THREAD_ID ) { // thread has invalid id
264 #ifdef DEBUG_THREADS
265 PError << "B_BAD_THREAD_ID" << endl;
266 #endif
267 return TRUE;
270 return FALSE;
274 void PThread::Suspend(BOOL susp)
276 PAssert(!IsTerminated(), "Operation on terminated thread");
277 if (susp)
279 status_t result = ::suspend_thread(threadId);
281 PAssert(result == B_OK, "Thread don't want to be suspended");
283 else
284 Resume();
288 void PThread::Resume()
290 PAssert(!IsTerminated(), "Operation on terminated thread");
291 status_t result = ::resume_thread(threadId);
293 PAssert(result == B_NO_ERROR, "Thread doesn't want to resume");
297 BOOL PThread::IsSuspended() const
299 thread_info info;
300 status_t result = ::get_thread_info(threadId, &info);
302 PAssert(result == B_OK && threadId == info.thread, "Thread info inaccessible");
303 return info.state == B_THREAD_SUSPENDED;
306 void PThread::SetAutoDelete(AutoDeleteFlag deletion)
308 PAssert(deletion != AutoDeleteThread || this != &PProcess::Current(), PLogicError);
309 autoDelete = deletion == AutoDeleteThread;
312 void PThread::SetPriority(Priority priorityLevel)
314 PAssert(!IsTerminated(), "Operation on terminated thread");
316 priority = priorities[priorityLevel];
317 status_t result = ::set_thread_priority(threadId, priority );
319 PAssert(result == B_OK, "Thread priority change error");
323 PThread::Priority PThread::GetPriority() const
325 PAssert(!IsTerminated(), "Operation on terminated thread");
327 switch (priority) {
328 case 0 :
329 return LowestPriority;
330 case B_LOW_PRIORITY :
331 return LowPriority;
332 case B_NORMAL_PRIORITY :
333 return NormalPriority;
334 case B_DISPLAY_PRIORITY :
335 return HighPriority;
336 case B_URGENT_DISPLAY_PRIORITY :
337 return HighestPriority;
339 PAssertAlways(POperatingSystemError);
340 return LowestPriority;
343 void PThread::Yield()
345 // we just sleep for long enough to cause a reschedule (100 microsec)
346 ::snooze(100);
349 void PThread::Sleep( const PTimeInterval & delay ) // Time interval to sleep for.
351 bigtime_t microseconds =
352 delay == PMaxTimeInterval ? B_INFINITE_TIMEOUT : (delay.GetMilliSeconds() * 1000 );
354 status_t result = ::snooze( microseconds ) ; // delay in ms, snooze in microsec
355 PAssert(result == B_OK, "Thread has insomnia");
358 void PThread::InitialiseProcessThread()
360 originalStackSize = 0;
361 autoDelete = FALSE;
363 threadId = ::find_thread(NULL);
364 PAssertOS(threadId >= B_NO_ERROR);
366 ((PProcess *)this)->activeThreads.DisallowDeleteObjects();
367 ((PProcess *)this)->activeThreads.SetAt(threadId, this);
371 PThread * PThread::Current()
373 PProcess & process = PProcess::Current();
374 process.activeThreadMutex.Wait();
376 thread_id tId = ::find_thread(NULL);
377 PAssertOS(tId >= B_NO_ERROR);
379 PThread * thread = process.activeThreads.GetAt( tId );
381 process.activeThreadMutex.Signal();
382 return thread;
385 int PThread::PXBlockOnChildTerminate(int pid, const PTimeInterval & /*timeout*/) // Fix timeout
387 status_t result = B_NO_ERROR;
388 status_t exit_value = B_NO_ERROR;
390 #ifdef DEBUG_THREADS
391 PError << "::wait_for_thread(" << pid << "), result:";
392 #endif
394 result = ::wait_for_thread(pid, &exit_value);
395 if ( result == B_INTERRUPTED ) { // thread was killed.
396 #ifdef DEBUG_THREADS
397 PError << "B_INTERRUPTED" << endl;
398 #endif
399 return 1;
402 if ( result == B_OK ) { // thread is dead
403 #ifdef DEBUG_THREADS
404 PError << "B_OK" << endl;
405 #endif
406 return 1;
409 if ( result == B_BAD_THREAD_ID ) { // thread has invalid id
410 #ifdef DEBUG_THREADS
411 PError << "B_BAD_THREAD_ID" << endl;
412 #endif
413 return 1;
416 return 0; // ???
419 PThreadIdentifier PThread::GetCurrentThreadId(void)
421 return ::find_thread(NULL);
424 int PThread::PXBlockOnIO(int handle, int type, const PTimeInterval & timeout)
426 // make sure we flush the buffer before doing a write
427 fd_set tmp_rfd, tmp_wfd, tmp_efd;
428 fd_set * read_fds = &tmp_rfd;
429 fd_set * write_fds = &tmp_wfd;
430 fd_set * exception_fds = &tmp_efd;
432 FD_ZERO (read_fds);
433 FD_ZERO (write_fds);
434 FD_ZERO (exception_fds);
436 switch (type) {
437 case PChannel::PXReadBlock:
438 case PChannel::PXAcceptBlock:
439 FD_SET (handle, read_fds);
440 break;
441 case PChannel::PXWriteBlock:
442 FD_SET (handle, write_fds);
443 break;
444 case PChannel::PXConnectBlock:
445 FD_SET (handle, write_fds);
446 FD_SET (handle, exception_fds);
447 break;
448 default:
449 PAssertAlways(PLogicError);
450 return 0;
453 struct timeval * tptr = NULL;
454 struct timeval timeout_val;
455 if (timeout != PMaxTimeInterval) { // Clean up for infinite timeout
456 static const PTimeInterval oneDay(0, 0, 0, 0, 1);
457 if (timeout < oneDay) {
459 timeout_val.tv_usec = (timeout.GetMilliSeconds() % 1000) * 1000;
460 timeout_val.tv_sec = timeout.GetSeconds();
461 tptr = &timeout_val;
465 int retval = ::select(handle+1, read_fds, write_fds, exception_fds, tptr);
466 PProcess::Current().PXCheckSignals();
468 return retval;
471 int PThread::PXBlockOnIO(int maxHandles,
472 fd_set & readBits,
473 fd_set & writeBits,
474 fd_set & exceptionBits,
475 const PTimeInterval & timeout,
476 const PIntArray & /*osHandles*/)
478 // make sure we flush the buffer before doing a write
479 fd_set * read_fds = &readBits;
480 fd_set * write_fds = &writeBits;
481 fd_set * exception_fds = &exceptionBits;
483 struct timeval * tptr = NULL;
484 struct timeval timeout_val;
485 if (timeout != PMaxTimeInterval) { // Clean up for infinite timeout
486 static const PTimeInterval oneDay(0, 0, 0, 0, 1);
487 if (timeout < oneDay) {
488 timeout_val.tv_usec = (timeout.GetMilliSeconds() % 1000) * 1000;
489 timeout_val.tv_sec = timeout.GetSeconds();
490 tptr = &timeout_val;
494 int retval = ::select(maxHandles, read_fds, write_fds, exception_fds, tptr);
495 PProcess::Current().PXCheckSignals();
496 return retval;
499 void PThread::PXAbortBlock(void) const
503 ///////////////////////////////////////////////////////////////////////////////
504 // PProcess
506 void PProcess::Construct()
508 houseKeeper=NULL;
510 CreateConfigFilesDictionary();
512 CommonConstruct();
515 PProcess::HouseKeepingThread::HouseKeepingThread()
516 : PThread(256*1024 , NoAutoDeleteThread, LowPriority, "HouseKeepingThread")
518 Resume();
521 void PProcess::HouseKeepingThread::Main()
523 PProcess & process = PProcess::Current();
525 while(1) {
527 process.deleteThreadMutex.Wait();
529 for (PINDEX i = 0; i < process.autoDeleteThreads.GetSize(); i++)
531 PThread * pThread = (PThread *)
532 process.autoDeleteThreads.GetAt(i);
533 if( pThread->IsTerminated() )
535 process.autoDeleteThreads.RemoveAt(i--);
539 process.deleteThreadMutex.Signal();
541 PTimeInterval nextTimer = process.timers.Process();
542 if (nextTimer != PMaxTimeInterval)
544 if ( nextTimer.GetInterval() > 10000 )
546 nextTimer = 10000;
550 breakBlock.Wait( nextTimer );
554 void PProcess::SignalTimerChange()
556 if ( !houseKeeper )
557 houseKeeper = new HouseKeepingThread;
558 else
559 houseKeeper->breakBlock.Signal();
562 BOOL PProcess::SetMaxHandles(int)
564 return TRUE;
567 PProcess::~PProcess()
569 Sleep(100); // Give threads time to die a natural death
571 if( houseKeeper )
572 delete houseKeeper;
574 // OK, if there are any left we get really insistent...
575 activeThreadMutex.Wait();
576 for (PINDEX i = 0; i < activeThreads.GetSize(); i++) {
577 PThread* pThread = activeThreads.GetAt(i);
578 if (pThread && (this != pThread) && !pThread->IsTerminated())
579 pThread->Terminate(); // With extreme prejudice
581 activeThreadMutex.Signal();
583 deleteThreadMutex.Wait();
584 autoDeleteThreads.RemoveAll();
585 deleteThreadMutex.Signal();
587 delete configFiles;
590 ///////////////////////////////////////////////////////////////////////////////
591 // PSemaphore
592 //#define DEBUG_SEMAPHORES
593 #define USE_BENAPHORES // Comment this line if you don't want benaphores
595 PSemaphore::PSemaphore(sem_id anId, int32 initialBenaphore, int32 param)
596 : semId( anId ), benaphoreCount(initialBenaphore)
598 #ifdef DEBUG_SEMAPHORES
599 PAssertOS(semId != 0);
600 #endif
603 PSemaphore::PSemaphore(unsigned initial, unsigned maxCount)
604 : semId(0), benaphoreCount(0)
606 PAssertOS(FALSE); // This constructor is never called
609 PSemaphore::~PSemaphore()
611 status_t result = B_NO_ERROR;
613 #ifdef DEBUG_SEMAPHORES
614 PAssertOS( semId >= B_NO_ERROR );
615 #endif
617 #ifdef DEBUG_SEMAPHORES
618 int32 semCnt = 0;
619 get_sem_count(semId, &semCnt);
620 PError << "::delete_sem " << semId << ", count:" << semCnt << endl;
621 #endif
623 if ( semId != 0 )
625 result = ::delete_sem(semId);
628 #ifdef DEBUG_SEMAPHORES
629 if( result != B_NO_ERROR )
630 PError << "::Error: " << strerror(result) << endl;
631 #endif
634 void PSemaphore::Wait()
636 status_t result = B_NO_ERROR;
638 #ifdef DEBUG_SEMAPHORES
639 PAssertOS( semId >= B_NO_ERROR );
640 #endif
642 #ifdef DEBUG_SEMAPHORES
643 PError << "PSemaphore::Wait, benaphore: " << benaphoreCount << endl;
644 #endif
646 #ifdef USE_BENAPHORES
647 if( atomic_add( &benaphoreCount, 1 ) > 0 ) {
648 #endif // USE_BENAPHORES
650 #ifdef DEBUG_SEMAPHORES
651 sem_info info;
652 get_sem_info(semId, &info);
653 PError << "::acquire_sem_etc, id: " << semId << " (" << info.name << "), count:" << info.count << endl;
654 #endif
656 while ((result = ::acquire_sem(semId)) == B_INTERRUPTED)
658 #ifdef DEBUG_SEMAPHORES
659 PError << "::acquire_sem_etc " << semId << ", interrupted!" << endl;
660 #endif
663 #ifdef DEBUG_SEMAPHORES
664 if( result != B_NO_ERROR )
665 PError << "::Error: " << strerror(result) << endl;
666 #endif
668 #ifdef USE_BENAPHORES
669 atomic_add(&benaphoreCount, -1);
671 #endif // USE_BENAPHORES
675 BOOL PSemaphore::Wait(const PTimeInterval & timeout)
677 status_t result = B_NO_ERROR;
679 #ifdef DEBUG_SEMAPHORES
680 PAssertOS( semId >= B_NO_ERROR );
681 #endif
683 #ifdef DEBUG_SEMAPHORES
684 PError << "PSemaphore::Wait(timeout), benaphore: " << benaphoreCount << endl;
685 #endif
687 #ifdef USE_BENAPHORES
688 if( atomic_add( &benaphoreCount, 1 ) > 0 ) {
689 #endif // USE_BENAPHORES
691 PInt64 ms = timeout.GetMilliSeconds();
692 bigtime_t microseconds =
693 ms? timeout == PMaxTimeInterval ? B_INFINITE_TIMEOUT : ( ms * 1000 ) : 0;
695 #ifdef DEBUG_SEMAPHORES
696 int32 semCnt = 0;
697 get_sem_count(semId, &semCnt);
698 PError << "::acquire_sem_etc " << semId << ", count:" << semCnt << ", timeout:";
700 if( microseconds == B_INFINITE_TIMEOUT )
701 PError << "infinite" << endl;
702 else
703 PError << microseconds << endl;
704 #endif
706 result = ::acquire_sem_etc(semId, 1,
707 B_RELATIVE_TIMEOUT, microseconds);
709 #ifdef DEBUG_SEMAPHORES
710 if( result != B_NO_ERROR )
712 PError << "::acquire_sem_etc " << semId << " with ";
713 if( microseconds == B_INFINITE_TIMEOUT )
714 PError << "infinite";
715 else
716 PError << microseconds;
717 PError << " timeout failed, Error: " << strerror(result) << endl;
719 #endif
721 #ifdef USE_BENAPHORES
722 atomic_add(&benaphoreCount, -1);
724 #endif // USE_BENAPHORES
726 return result == B_TIMED_OUT;
730 void PSemaphore::Signal()
732 #ifdef DEBUG_SEMAPHORES
733 PAssertOS( semId >= B_NO_ERROR );
734 #endif
736 #ifdef DEBUG_SEMAPHORES
737 PError << "PSemaphore::Wait(timeout), benaphore: " << benaphoreCount << endl;
738 #endif
740 #ifdef USE_BENAPHORES
741 if( atomic_add( &benaphoreCount, -1 ) > 1 )
743 #endif // USE_BENAPHORES
745 #ifdef DEBUG_SEMAPHORES
746 status_t result =
747 #endif
748 ::release_sem_etc(semId, 1, 0);
750 #ifdef DEBUG_SEMAPHORES
751 if( result != B_NO_ERROR )
752 PError << "::Error:" << strerror(result) << endl;
753 #endif
755 #ifdef USE_BENAPHORES
757 #endif // USE_BENAPHORES
761 BOOL PSemaphore::WillBlock() const
763 status_t result = B_NO_ERROR;
765 #ifdef DEBUG_SEMAPHORES
766 PAssertOS( semId >= B_NO_ERROR );
767 #endif
769 #ifdef USE_BENAPHORES
770 if( atomic_add( (volatile int32*) &benaphoreCount, -1 ) > 1 )
772 #endif // USE_BENAPHORES
774 #ifdef DEBUG_SEMAPHORES
775 int32 semCnt = 0;
776 get_sem_count(semId, &semCnt);
777 PError << "::acquire_sem_etc (WillBlock) " << semId << ", count:" << semCnt << endl;
778 #endif
780 result = ::acquire_sem_etc(semId, 0, B_RELATIVE_TIMEOUT, 0);
782 #ifdef DEBUG_SEMAPHORES
783 if( result != B_NO_ERROR )
784 PError << "::Error:" << strerror(result) << endl;
785 #endif
787 #ifdef USE_BENAPHORES
789 #endif // USE_BENAPHORES
791 return result == B_WOULD_BLOCK;
794 ///////////////////////////////////////////////////////////////////////////////
795 // PMutex
797 PMutex::PMutex()
798 : PSemaphore( ::create_sem(1, "PWLM" ) , 0 )
800 #ifdef DEBUG_SEMAPHORES
801 PError << "::create_sem(PMutex) " << semId << endl;
802 PAssertOS( semId >= B_NO_ERROR );
803 #endif
806 void PMutex::Wait()
808 PSemaphore::Wait();
811 BOOL PMutex::Wait(const PTimeInterval & timeout)
813 return PSemaphore::Wait(timeout);
816 void PMutex::Signal()
818 PSemaphore::Signal();
821 BOOL PMutex::WillBlock() const
823 return PSemaphore::WillBlock();
826 ///////////////////////////////////////////////////////////////////////////////
827 // PSyncPoint
829 PSyncPoint::PSyncPoint()
830 : PSemaphore( ::create_sem(0, "PWLP" ), 1 )
832 #ifdef DEBUG_SEMAPHORES
833 PError << "::create_sem(PSyncPoint) " << semId << endl;
834 #endif
836 PAssertOS( semId >= B_NO_ERROR );
839 void PSyncPoint::Signal()
841 PSemaphore::Signal();
844 void PSyncPoint::Wait()
846 PSemaphore::Wait();
849 BOOL PSyncPoint::Wait(const PTimeInterval & timeout)
851 return PSemaphore::Wait(timeout);
854 BOOL PSyncPoint::WillBlock() const
856 return PSemaphore::WillBlock();
859 //////////////////////////////////////////////////////////////////////////////
860 // Extra functionality not found in BeOS
862 int seteuid(uid_t uid) { return 0; }
863 int setegid(gid_t gid) { return 0; }
865 // End Of File ///////////////////////////////////////////////////////////////