📄 tlibbe.cxx
字号:
/*
* tlibbe.cxx
*
* Thread library implementation for BeOS
*
* Portable Windows Library
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.0 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS"
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
* the License for the specific language governing rights and limitations
* under the License.
*
* The Original Code is Portable Windows Library.
*
* The Initial Developer of the Original Code is Equivalence Pty. Ltd.
*
* Portions are Copyright (c) 1993-1998 Equivalence Pty. Ltd.
*
* Portions are Copyright (C) 1993 Free Software Foundation, Inc.
* All Rights Reserved.
*
* Contributor(s): Yuri Kiryanov, ykiryanov at users.sourceforge.net
*
* $Revision: 19516 $
* $Author: rjongbloed $
* $Date: 2008-02-14 08:05:40 +0000 (Thu, 14 Feb 2008) $
*/
class PThread;
class PProcess;
class PSemaphore;
class PSyncPoint;
class PMutex;
#include <ptlib.h>
#include <ptlib/socket.h>
#ifdef B_ZETA_VERSION
#include <posix/rlimit.h>
#endif // Zeta
// For class BLocker
#include <be/support/Locker.h>
int PX_NewHandle(const char *, int);
#define DEBUG_SEMAPHORES1 1
//////////////////////////////////////////////////////////////////////////////
// Threads
static int const priorities[] = {
1, // Lowest priority is 1. 0 is not
B_LOW_PRIORITY,
B_NORMAL_PRIORITY,
B_DISPLAY_PRIORITY,
B_URGENT_DISPLAY_PRIORITY,
};
int32 PThread::ThreadFunction(void * threadPtr)
{
PThread * thread = (PThread *)PAssertNULL(threadPtr);
PProcess & process = PProcess::Current();
process.threadMutex.Wait();
process.activeThreads.SetAt((unsigned) thread->mId, thread);
process.threadMutex.Signal();
process.OnThreadStart(*thread);
thread->Main();
process.OnThreadEnded(*thread);
return 0;
}
PThread::PThread()
: autoDelete(PTrue),
mId(B_BAD_THREAD_ID),
mPriority(B_NORMAL_PRIORITY),
mStackSize(0),
mSuspendCount(0)
{
}
void PThread::InitialiseProcessThread()
{
autoDelete = PFalse;
mId = find_thread(NULL);
mPriority = B_NORMAL_PRIORITY;
mStackSize = 0;
mSuspendCount = 1;
PAssert(::pipe(unblockPipe) == 0, "Pipe creation failed in InitialiseProcessThread!");
PAssertOS(unblockPipe[0]);
PAssertOS(unblockPipe[1]);
((PProcess *)this)->activeThreads.DisallowDeleteObjects();
((PProcess *)this)->activeThreads.SetAt(mId, this);
}
PThread::PThread(PINDEX stackSize,
AutoDeleteFlag deletion,
Priority priorityLevel,
const PString & name)
: mId(B_BAD_THREAD_ID),
mPriority(B_NORMAL_PRIORITY),
mStackSize(0),
mSuspendCount(0)
{
PAssert(stackSize > 0, PInvalidParameter);
autoDelete = deletion == AutoDeleteThread;
mId = ::spawn_thread(ThreadFunction, // Function
(const char*) name, // Name
priorities[priorityLevel], // Priority
(void *) this); // Pass this as cookie
PAssertOS(mId >= B_NO_ERROR);
mSuspendCount = 1;
mStackSize = stackSize;
mPriority = priorities[priorityLevel];
threadName.sprintf(name, mId);
::rename_thread(mId, (const char*) threadName); // real, unique name - with id
PAssert(::pipe(unblockPipe) == 0, "Pipe creation failed in PThread constructor");
PX_NewHandle("Thread unblock pipe", PMAX(unblockPipe[0], unblockPipe[1]));
}
PThread * PThread::Current()
{
PProcess & process = PProcess::Current();
process.threadMutex.Wait();
PThread * thread = process.activeThreads.GetAt((unsigned)find_thread(NULL));
process.threadMutex.Signal();
return thread;
}
PThread::~PThread()
{
// if we are not process, remove this thread from the active thread list
PProcess & process = PProcess::Current();
if(process.GetThreadId() != GetThreadId())
{
process.threadMutex.Wait();
process.activeThreads.RemoveAt((unsigned) mId);
process.threadMutex.Signal();
}
if (!IsTerminated())
Terminate();
::close(unblockPipe[0]);
::close(unblockPipe[1]);
}
void PThread::Restart()
{
if(!IsTerminated())
return;
mId = ::spawn_thread(ThreadFunction, // Function
"PWLT", // Name
mPriority,
(void *) this); // Pass this as cookie
PAssertOS(mId >= B_NO_ERROR);
threadName.sprintf("PWLib Thread %d", mId);
::rename_thread(mId, (const char*) threadName); // real, unique name - with id
}
void PThread::Terminate()
{
if(mStackSize <=0)
return;
if(mId == find_thread(NULL))
{
::exit_thread(0);
return;
}
if(IsTerminated())
return;
PXAbortBlock();
WaitForTermination(20);
if(mId > B_BAD_THREAD_ID)
::kill_thread(0);
}
PBoolean PThread::IsTerminated() const
{
return mId == B_BAD_THREAD_ID;
}
void PThread::WaitForTermination() const
{
WaitForTermination(PMaxTimeInterval);
}
PBoolean PThread::WaitForTermination(const PTimeInterval & /*maxWait*/) const // Fix timeout
{
status_t result = B_NO_ERROR;
status_t exit_value = B_NO_ERROR;
result = ::wait_for_thread(mId, &exit_value);
if ( result == B_INTERRUPTED ) { // thread was killed.
return PTrue;
}
if ( result == B_OK ) { // thread is dead
#ifdef DEBUG_THREADS
PError << "B_OK" << endl;
#endif
return PTrue;
}
if ( result == B_BAD_THREAD_ID ) { // thread has invalid id
return PTrue;
}
return PFalse;
}
void PThread::Suspend(PBoolean susp)
{
PAssert(!IsTerminated(), "Operation on terminated thread");
if (susp)
{
status_t result = ::suspend_thread(mId);
if(B_OK == result)
::atomic_add(&mSuspendCount, 1);
PAssert(result == B_OK, "Thread don't want to be suspended");
}
else
Resume();
}
void PThread::Resume()
{
PAssert(!IsTerminated(), "Operation on terminated thread");
status_t result = ::resume_thread(mId);
if(B_OK == result)
::atomic_add(&mSuspendCount, -1);
PAssert(result == B_NO_ERROR, "Thread doesn't want to resume");
}
PBoolean PThread::IsSuspended() const
{
return (mSuspendCount > 0);
}
void PThread::SetAutoDelete(AutoDeleteFlag deletion)
{
PAssert(deletion != AutoDeleteThread || this != &PProcess::Current(), PLogicError);
autoDelete = deletion == AutoDeleteThread;
}
void PThread::SetPriority(Priority priorityLevel)
{
PAssert(!IsTerminated(), "Operation on terminated thread");
mPriority = priorities[priorityLevel];
status_t result = ::set_thread_priority(mId, mPriority );
if(result != B_OK)
PTRACE(0, "Changing thread priority failed, error " << strerror(result) << endl);
}
PThread::Priority PThread::GetPriority() const
{
if(!IsTerminated())
{
switch (mPriority) {
case 0 :
return LowestPriority;
case B_LOW_PRIORITY :
return LowPriority;
case B_NORMAL_PRIORITY :
return NormalPriority;
case B_DISPLAY_PRIORITY :
return HighPriority;
case B_URGENT_DISPLAY_PRIORITY :
return HighestPriority;
}
PAssertAlways(POperatingSystemError);
}
return LowestPriority;
}
void PThread::Yield()
{
// we just sleep for long enough to cause a reschedule (100 microsec)
::snooze(100);
}
void PThread::Sleep( const PTimeInterval & delay ) // Time interval to sleep for.
{
bigtime_t microseconds =
delay == PMaxTimeInterval ? B_INFINITE_TIMEOUT : (delay.GetMilliSeconds() * 1000 );
status_t result = ::snooze( microseconds ) ; // delay in ms, snooze in microsec
PAssert(result == B_OK, "Thread has insomnia");
}
int PThread::PXBlockOnChildTerminate(int pid, const PTimeInterval & /*timeout*/) // Fix timeout
{
status_t result = B_NO_ERROR;
status_t exit_value = B_NO_ERROR;
result = ::wait_for_thread(pid, &exit_value);
if ( result == B_INTERRUPTED )
{
// thread was killed.
#ifdef DEBUG_THREADS
PError << "B_INTERRUPTED" << endl;
#endif
return 1;
}
if ( result == B_OK )
{
// thread is dead
return 1;
}
if ( result == B_BAD_THREAD_ID )
{
// thread has invalid id
return 1;
}
return 0; // ???
}
PThreadIdentifier PThread::GetCurrentThreadId(void)
{
return ::find_thread(NULL);
}
int PThread::PXBlockOnIO(int handle, int type, const PTimeInterval & timeout)
{
PTRACE(7, "PWLib\tPThread::PXBlockOnIO(" << handle << ',' << type << ')');
if ((handle < 0) || (handle >= PProcess::Current().GetMaxHandles())) {
PTRACE(2, "PWLib\tAttempt to use illegal handle in PThread::PXBlockOnIO, handle=" << handle);
errno = EBADF;
return -1;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -