⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 tlibmpthrd.cxx

📁 sloedgy open sip stack source code
💻 CXX
📖 第 1 页 / 共 2 页
字号:
                      (void *)this, // param 2 == "PThread to clean up"
                      0, // no options
                      &PX_threadId);
  PAssert(err == 0, "MPCreateTask failed");
  if (err) throw std::bad_alloc();

}

long PThread::PX_ThreadStart(void * arg)
{ 
  MPTaskID threadId = MPCurrentTaskID();

  // self-detach (no need)

  PThread * thread = (PThread *)arg;
  thread->SetThreadName(thread->GetThreadName());

  PProcess & process = PProcess::Current();

  // add thread to thread list
  process.threadMutex.Wait();
  process.activeThreads.SetAt((unsigned)threadId, thread);
  process.threadMutex.Signal();

  // if we are not supposed to start suspended, then don't wait
  // if we are supposed to start suspended, then wait for a resume

  if (thread->PX_suspendCount != 0) {
    thread->suspend_semaphore->Wait();	// Wait for the Resume
  }

  // now call the the thread main routine
  //PTRACE(1, "tlibthrd\tAbout to call Main");
  thread->Main();

#ifdef DEBUG_THREADS
  if (debug_mpthreads)
      fprintf(stderr,"thread %p returning\n", thread);
#endif
  return 0;
}

#ifndef _DEBUG
#undef PMEMORY_CHECK
#endif

void PProcess::SignalTimerChange()
{
  if (housekeepingThread == NULL) {
#if PMEMORY_CHECK
    BOOL oldIgnoreAllocations = PMemoryHeap::SetIgnoreAllocations(TRUE);
#endif
    housekeepingThread = new PHouseKeepingThread;
#if PMEMORY_CHECK
    PMemoryHeap::SetIgnoreAllocations(oldIgnoreAllocations);
#endif
  }

  SetUpTermQueue();
  MPNotifyQueue(terminationNotificationQueue, 0, 0, 0);
}


void PThread::PX_ThreadEnd(void * arg)
{
  PThread * thread = (PThread *)arg;
  PProcess & process = PProcess::Current();
  
  MPTaskID id = thread->PX_GetThreadId();
  if (id != 0) {

    // remove this thread from the active thread list
    process.threadMutex.Wait();
    process.activeThreads.SetAt((unsigned)id, NULL);
    process.threadMutex.Signal();
  }

  // delete the thread if required, note this is done this way to avoid
  // a race condition, the thread ID cannot be zeroed before the if!
  if (thread->autoDelete) {
    thread->PX_threadId = 0;  // Prevent terminating terminated thread
    delete thread;
  }
  else
    thread->PX_threadId = 0;
}


MPTaskID PThread::PX_GetThreadId() const
{
  return PX_threadId;
}


void PThread::Restart()
{
  if (IsTerminated())
    return;

  PX_NewThread(FALSE);
}


void PThread::Terminate()
{
  if (PX_origStackSize <= 0)
    return;

  if (IsTerminated())
    return;

  PTRACE(1, "tlibthrd\tForcing termination of thread " << (void *)this);

  if (Current() == this)
      MPExit(0);
  else {
      MPTaskID taskId = PX_threadId;
      WaitForTermination();
      // XXX Dire Consequences[TM] are warned of when one uses MPTerminateTask.
      // XXX However, the same Dire Consequences are predicted (I think) for
      // XXX pthread_kill which the PWLIB code already uses.
      // XXX However, the only thing the cleanup function does is removes the
      // XXX thread from the thread table, which is already performed by the
      // XXX housekeeping thread; PWLIB doesn't try to salvage locks or
      // XXX anything clever like that.
      // XXX I just hope taskIds aren't quickly reused.
      if (taskId != 0)
          (void)MPTerminateTask(taskId, kMPTaskAbortedErr);
  }
}


void PThread::PXSetWaitingSemaphore(PSemaphore * sem)
{
    // not needed
}


BOOL PThread::IsTerminated() const
{
  if (PX_threadId == 0) {
    //PTRACE(1, "tlibthrd\tIsTerminated(" << (void *)this << ") = 0");
    return TRUE;
  }

#ifdef _not_def_ // Sigh.  no MPGetNextTaskID on MOSX
  // This seems like a silly way to do this, but I think it might work.
  // The end condition for MPGetNextTaskID isn't documented, so I try both
  // logical possibilities.
  MPTaskID sometask = 0;
  MPProcessID myproc = 0;
  while (MPGetNextTaskID(myproc, &sometask) == noErr) {
      if (sometask == 0) break;
      if (sometask == PX_threadId) {
          //PTRACE(1, "tlibthrd\tIsTerminated(" << (void *)this << ") not dead yet");
          return FALSE;
      }
  }
  // didn't find it, it's dead
  //PTRACE(1, "tlibthrd\tIsTerminated(" << (void *)this << ") = 0");
  return TRUE;
#else
  return FALSE; // ENOCLUE
#endif
}

// Mac OS X and Darwin 1.2 does not support pthread_kill() or sigwait()
// so we cannot implement suspend and resume using signals. Instead we have a
// partial implementation using a Semaphore.
// As a result, we can create a thread in a suspended state and then 'resume'
// it, but once it is going, we can no longer suspend it.
// So, for Mac OS X, we will accept Resume() calls (or Suspend(FALSE))
// but reject Suspend(TRUE) calls with an Assertion. This will indicate
// to a user that we cannot Suspend threads on Mac OS X

void PThread::Suspend(BOOL susp)
{
  OSStatus err;
  err = MPWaitOnSemaphore(PX_suspendMutex,kDurationForever);
  PAssert(err == 0, "MPWaitOnSemaphore failed");

  if (susp) {
    // Suspend - warn the user with an Assertion
    PAssertAlways("Cannot suspend threads on Mac OS X due to lack of pthread_kill()");
  }

  // if resuming, then see if to really resume
  else if (PX_suspendCount > 0) {
    PX_suspendCount--;
    if (PX_suspendCount == 0)  {
      suspend_semaphore->Signal();
    }
  }

  err = MPSignalSemaphore(PX_suspendMutex);
  PAssert( err == 0, "MPSignalSemaphore failed");
}

void PThread::Resume()
{
  Suspend(FALSE);
}


BOOL PThread::IsSuspended() const
{
  OSStatus err;

  if (IsTerminated())
    return FALSE;

  err = MPWaitOnSemaphore(PX_suspendMutex, kDurationForever);
  PAssert(err == 0, "MPWaitOnSemaphore failed");
  BOOL suspended = PX_suspendCount > 0;
  err = MPSignalSemaphore(PX_suspendMutex);
  PAssert(err == 0, "MPSignalSemaphore failed");
  return suspended;
}


void PThread::SetAutoDelete(AutoDeleteFlag deletion)
{
  PAssert(deletion != AutoDeleteThread || this != &PProcess::Current(), PLogicError);
  autoDelete = deletion == AutoDeleteThread;
}


void PThread::SetPriority(Priority /*priorityLevel*/)
{
}


PThread::Priority PThread::GetPriority() const
{
  return LowestPriority;
}


void PThread::Yield()
{
  ::sleep(0);
}


PThread * PThread::Current()
{
  PProcess & process = PProcess::Current();
  process.threadMutex.Wait();
  PThread * thread = process.activeThreads.GetAt((unsigned)MPCurrentTaskID());
  process.threadMutex.Signal();
  return PAssertNULL(thread);
}


void PThread::Sleep(const PTimeInterval & timeout)
{
    AbsoluteTime expiry;
    Duration delta = kDurationForever;
    
    if (timeout != PMaxTimeInterval) {
        delta = timeout.GetMilliSeconds();
    }
    expiry = AddDurationToAbsolute(delta, UpTime());
    
    (void)MPDelayUntil(&expiry);
}


void PThread::WaitForTermination() const
{
  PAssert(Current() != this, "Waiting for self termination!");
  
  PXAbortBlock();

  while (!IsTerminated()) {
    PAssert(PX_signature == kMPThreadSig, "bad signature in living thread");
    Current()->Sleep(10);
#ifdef DEBUG_THREADS
    if (debug_mpthreads)
        fprintf(stderr,"spinning for termination of thread %p\n", (void *)this);
#endif  
    if (noHousekeeper) PollNotificationQueue(kDurationImmediate);
  }
}


BOOL PThread::WaitForTermination(const PTimeInterval & maxWait) const
{
  PAssert(Current() != this, "Waiting for self termination!");
  
  //PTRACE(1, "tlibthrd\tWaitForTermination(delay)");
  PXAbortBlock();

  PTimer timeout = maxWait;
  while (!IsTerminated()) {
    if (timeout == 0)
      return FALSE;
    Current()->Sleep(10);
  }
  return TRUE;
}


///////////////////////////////////////////////////////////////////////////////

PSemaphore::PSemaphore(unsigned initial, unsigned maxCount)
{
    OSStatus err = MPCreateSemaphore(maxCount, initial, &semId);
    PAssert(err == 0, "MPCreateSemaphore failed");
    PAssert((long)semId != 0 && (long)semId != -1, "stupid semId");
}


PSemaphore::~PSemaphore()
{
    OSStatus err = MPDeleteSemaphore(semId);
    PAssert(err == 0, "MPDeleteSemaphore failed");
    *(long *)&semId = -1;
}


void PSemaphore::Wait()
{
    assert((long)semId != 0);
    assert((long)semId != -1);
    
    PAssert((long)semId != -1, "wait on destructed PSemaphore");
    PAssert((long)semId != 0, "semId stomped");
    OSStatus err = MPWaitOnSemaphore(semId, kDurationForever);
    PAssert(err == 0, "MPWaitOnSemaphore failed");
}


BOOL PSemaphore::Wait(const PTimeInterval & waitTime)
{
  OSErr err = 0;
    
  if (waitTime == PMaxTimeInterval) {
    Wait();
    return TRUE;
  }

  Duration timeout = waitTime.GetMilliSeconds();
  if ((err = MPWaitOnSemaphore(semId, timeout)) == noErr)
      return TRUE;
  if (err == kMPTimeoutErr)
      return FALSE;
  PAssert(err == 0, psprintf("timed wait error = %i", err));
  return FALSE;
}

void PSemaphore::Signal()
{
    OSStatus err = MPSignalSemaphore(semId);
    // was it already signalled?
    if (err == kMPInsufficientResourcesErr) err = 0;
    PAssert(err == 0, "MPSignalSemaphore failed");
}


BOOL PSemaphore::WillBlock() const
{
    OSStatus err = MPWaitOnSemaphore(semId, kDurationImmediate);
    if (err == kMPTimeoutErr)
        return TRUE;
    PAssert(err == 0, psprintf("timed wait error = %i", err));
    (void)MPSignalSemaphore(semId);
    return FALSE;
}

// Ideally, a PMutex would contain an MPCriticalSection instead of a
// semaphore, but the class derivation is outside the machine-specific
// code, and I'm unwilling to do something gross like implement a bogus
// constructor for PSemaphore which doesn't allocate a semaphore.

PMutex::PMutex()
  : PSemaphore(1, 1)
{
}

void PMutex::Wait()
{
	PSemaphore::Wait();
}

BOOL PMutex::Wait(const PTimeInterval & timeout)
{
	return PSemaphore::Wait(timeout);
}

void PMutex::Signal()
{
	PSemaphore::Signal();
}

BOOL PMutex::WillBlock() const 
{
	return PSemaphore::WillBlock();
}

PSyncPoint::PSyncPoint()
  : PSemaphore(0, 1)
{
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -