📄 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>///////////////////////////////////////////////////////////////////////////////// Threadsstatic 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, const PString & name) : threadName(name){ 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);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -