📄 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, BeVox Group, yk@altavista.net.
*/
class PProcess;
class PSemaphore;
#include <ptlib.h>
///////////////////////////////////////////////////////////////////////////////
// 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.activeThreadMutex.Wait();
process.activeThreads.SetAt(thread->threadId, thread);
process.activeThreadMutex.Signal();
process.SignalTimerChange();
thread->Main();
return 0;
}
PThread::PThread()
: threadId(B_BAD_THREAD_ID),
priority(B_NORMAL_PRIORITY),
originalStackSize(0)
{
}
PThread::PThread(PINDEX stackSize,
AutoDeleteFlag deletion,
Priority priorityLevel)
{
PAssert(stackSize > 0, PInvalidParameter);
autoDelete = deletion == AutoDeleteThread;
originalStackSize = stackSize;
priority = priorities[priorityLevel];
threadId = ::spawn_thread(ThreadFunction, // Function
"PWLT", // Name
priority, // Priority
(void *) this); // Pass this as cookie
PAssertOS(threadId >= B_NO_ERROR);
if (autoDelete) {
PProcess & process = PProcess::Current();
process.deleteThreadMutex.Wait();
process.autoDeleteThreads.Append(this);
process.deleteThreadMutex.Signal();
}
}
PThread::~PThread()
{
if (originalStackSize <= 0)
return;
PProcess & process = PProcess::Current();
process.activeThreadMutex.Wait();
process.activeThreads.SetAt(threadId, NULL);
process.activeThreadMutex.Signal();
if (!IsTerminated())
Terminate();
}
void PThread::Restart()
{
PAssert(IsTerminated(), "Cannot restart running thread");
threadId = ::spawn_thread(ThreadFunction, // Function
"PWLT", // Name
priority,
(void *) this); // Pass this as cookie
PAssertOS(threadId >= B_NO_ERROR);
}
void PThread::Terminate()
{
PAssert(!IsTerminated(), "Operation on terminated thread");
PAssert(originalStackSize > 0, PLogicError);
if (Current() == this)
{
sem_id semId = ::create_sem( 1, "PWST" );
if ( ::acquire_sem(semId) == B_NO_ERROR )
{
// Invalidate the thread
threadId = B_BAD_THREAD_ID;
::release_sem(semId);
::delete_sem(semId);
::exit_thread(0);
}
}
else
{
sem_id semId = ::create_sem( 1, "PWTS" );
if ( ::acquire_sem(semId) == B_NO_ERROR )
{
thread_id tId(B_BAD_THREAD_ID);
// Invalidate the thread
tId = threadId;
threadId = B_BAD_THREAD_ID;
// Kill it
if (tId != B_BAD_THREAD_ID)
{
::release_sem(semId);
::delete_sem(semId);
::kill_thread(tId);
}
}
}
PAssert(threadId == B_BAD_THREAD_ID, "Can't acquire semaphore to terminate thread");
}
BOOL PThread::IsTerminated() const
{
return threadId == B_BAD_THREAD_ID;
}
void PThread::WaitForTermination() const
{
WaitForTermination(PMaxTimeInterval);
}
BOOL PThread::WaitForTermination(const PTimeInterval & /*maxWait*/) const // Fix timeout
{
if (threadId == 0)
return TRUE;
status_t result, exit_value;
PINDEX retries = 10;
while ((result = ::wait_for_thread(threadId, &exit_value) != B_NO_ERROR)) {
if ( result == B_INTERRUPTED ) { // thread was killed.
return TRUE;
}
if (retries > 0)
return TRUE;
retries--;
}
return FALSE;
}
void PThread::Suspend(BOOL susp)
{
PAssert(!IsTerminated(), "Operation on terminated thread");
if (susp)
{
status_t result = ::suspend_thread(threadId);
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(threadId);
PAssert(result == B_NO_ERROR, "Thread doesn't want to resume");
}
BOOL PThread::IsSuspended() const
{
PAssert(!IsTerminated(), "Operation on terminated thread");
thread_info info;
status_t result = ::get_thread_info(threadId, &info);
PAssert(result == B_OK && threadId == info.thread, "Thread info inaccessible");
return info.state == B_THREAD_SUSPENDED;
}
void PThread::SetPriority(Priority priorityLevel)
{
PAssert(!IsTerminated(), "Operation on terminated thread");
priority = priorities[priorityLevel];
status_t result = ::set_thread_priority(threadId, priority );
PAssert(result == B_OK, "Thread priority change error");
}
PThread::Priority PThread::GetPriority() const
{
PAssert(!IsTerminated(), "Operation on terminated thread");
switch (priority) {
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");
}
void PThread::InitialiseProcessThread()
{
originalStackSize = 0;
autoDelete = FALSE;
threadId = ::find_thread(NULL);
PAssertOS(threadId >= B_NO_ERROR);
((PProcess *)this)->activeThreads.DisallowDeleteObjects();
((PProcess *)this)->activeThreads.SetAt(threadId, this);
}
PThread * PThread::Current()
{
PProcess & process = PProcess::Current();
process.activeThreadMutex.Wait();
thread_id tId = ::find_thread(NULL);
PAssertOS(tId >= B_NO_ERROR);
PThread * thread = process.activeThreads.GetAt( tId );
process.activeThreadMutex.Signal();
return thread;
}
int PThread::PXBlockOnChildTerminate(int pid, const PTimeInterval & /*timeout*/) // Fix timeout
{
status_t result, exit_value;
while ((result = ::wait_for_thread(pid, &exit_value) != B_NO_ERROR));
return exit_value;
}
int PThread::PXBlockOnIO(int handle, int type, const PTimeInterval & timeout)
{
// make sure we flush the buffer before doing a write
fd_set tmp_rfd, tmp_wfd, tmp_efd;
fd_set * read_fds = &tmp_rfd;
fd_set * write_fds = &tmp_wfd;
fd_set * exception_fds = &tmp_efd;
FD_ZERO (read_fds);
FD_ZERO (write_fds);
FD_ZERO (exception_fds);
switch (type) {
case PChannel::PXReadBlock:
case PChannel::PXAcceptBlock:
FD_SET (handle, read_fds);
break;
case PChannel::PXWriteBlock:
FD_SET (handle, write_fds);
break;
case PChannel::PXConnectBlock:
FD_SET (handle, write_fds);
FD_SET (handle, exception_fds);
break;
default:
PAssertAlways(PLogicError);
return 0;
}
struct timeval * tptr = NULL;
struct timeval timeout_val;
if (timeout != PMaxTimeInterval) { // Clean up for infinite timeout
static const PTimeInterval oneDay(0, 0, 0, 0, 1);
if (timeout < oneDay) {
timeout_val.tv_usec = (timeout.GetMilliSeconds() % 1000) * 1000;
timeout_val.tv_sec = timeout.GetSeconds();
tptr = &timeout_val;
}
}
int retval = ::select(handle+1, read_fds, write_fds, exception_fds, tptr);
//YK PProcess::Current().PXCheckSignals();
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -