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

📄 tlibmpthrd.cxx

📁 安装 H323需要的pwlib库
💻 CXX
📖 第 1 页 / 共 2 页
字号:
/* * tlibmpthrd.cxx * * Routines for Macintosh pre-emptive threading system * * Portable Windows Library * * Copyright (c) 1993-1998 Equivalence Pty. Ltd. * * 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 Free Software Foundation, Inc. * All Rights Reserved. * * Contributor(s): ______________________________________. * * $Log: tlibmpthrd.cxx,v $ * Revision 1.4  2002/06/27 06:38:58  robertj * Changes to remove memory leak display for things that aren't memory leaks. * * Revision 1.3  2002/02/19 07:40:59  rogerh * Remove PMutex destructor for Carbon. * * Revision 1.2  2002/02/19 07:28:02  rogerh * PXAbortIO -> PXAbortBlock. Submitted by Peter Johnson <paj@mac.com> * * Revision 1.1  2001/08/11 15:38:43  rogerh * Add Mac OS Carbon changes from John Woods <jfw@jfwhome.funhouse.com> * */#include <sys/resource.h>#include <new> // just because I want to throw std::bad_alloc...#ifndef NDEBUG#define DEBUG_THREADSextern int debug_mpthreads;#endifPDECLARE_CLASS(PHouseKeepingThread, PThread)  public:    PHouseKeepingThread()      : PThread(1000, NoAutoDeleteThread, NormalPriority, "Housekeeper")      { closing = FALSE; Resume(); }    void Main();    void SetClosing() { closing = TRUE; }  protected:    BOOL closing;};#define new PNEWint PThread::PXBlockOnIO(int handle, int type, const PTimeInterval & timeout){  //PTRACE(1,"PThread::PXBlockOnIO(" << handle << ',' << type << ')');  // 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;  struct timeval * tptr = NULL;  struct timeval   timeout_val;  if (timeout != PMaxTimeInterval) {    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;  for (;;) {    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;    }    // include the termination pipe into all blocking I/O functions    int width = handle+1;    FD_SET(unblockPipe[0], read_fds);    width = PMAX(width, unblockPipe[0]+1);      retval = ::select(width, read_fds, write_fds, exception_fds, tptr);    if ((retval >= 0) || (errno != EINTR))      break;  }  if ((retval == 1) && FD_ISSET(unblockPipe[0], read_fds)) {    BYTE ch;    ::read(unblockPipe[0], &ch, 1);    errno = EINTR;    retval =  -1;    //PTRACE(1,"Unblocked I/O");  }  return retval;}void PThread::PXAbortBlock() const{  BYTE ch;  ::write(unblockPipe[1], &ch, 1);}// For Mac OS, the housekeeping thread has two jobs:// First, poll for synchronous signals (as is traditional), and// second, to poll the MPThread termination notification queue and clean up// deceased PThreads.  // There is an ickiness here which depends on a current restriction of // Mac OS X:  synchronous signals (i.e. not signals resulting from// exceptions) are only delivered to the main thread.  I assume that// it is therefore safe for the main thread to call MPNotifyQueue from// a signal handler if and only if the main thread never calls MPNotifyQueue// on the termination notification queue from its main code.  This ought to// be acceptable if notifying a queue is single-threaded per queue; if// MPNotifyQueue has a global critical section, this will work very badly.static MPQueueID terminationNotificationQueue = 0;// This bites.  Threads don't know what process they come from (even though// there can be only one), yet when we're winding down the process thread// kills the housekeeper before it can clean up all the other threads.// So the process thread has to poll the termination queue, but it does so// from PThread context, so it can't know there's no housekeeper.  yuck.static BOOL noHousekeeper = 0;static void SetUpTermQueue() {    OSStatus err;    // Let us PLEASE try not to get into any "create/delete" loops here.    // Create it and be DONE with it.    while (!terminationNotificationQueue) {        MPQueueID tempQueue;        err = MPCreateQueue(&tempQueue);        PAssert(err == noErr, "MPCreateQueue failed");        // When Motorola finally finishes the 620, there's a lot of Mac code        // gonna need to be rewritten.        // HAHAHAHAHAHAHAHAHAHAHAHAHAHAHAHAHAHAHAHAHAHAHAHAHAHAHAHAHAHAHAHA!!!        // "finishes the 620".  hee hee hee!        if (!OTCompareAndSwap32(0, (UInt32)tempQueue,                                (UInt32*)&terminationNotificationQueue)) {            // then someone else snuck in and initialized it.            MPDeleteQueue(tempQueue);        } else {#ifdef DEBUG_THREADS            if (debug_mpthreads)                fprintf(stderr,"set up notification queue\n");#endif            // XXX MPNotifyQueue is perfectly willing to allocate memory            // XXX for the items dropped in the queue.  However, if it can't,            // XXX then life just goes on -- and we miss a thread exit message.            // XXX If we reserve queue space, however, then we guarantee two            // XXX things:  1, we absolutely will be able to receive N            // XXX notifications, and 2, we absolutely will drop the N+1st            // XXX on the floor, spare memory or no.  The target applications            // XXX for this library do not appear (currently) to generate            // XXX absurd numbers of threads, so I'll reserve an absurd number            // XXX of messages, and pretend that nothing can go wrong.            // XXX n go wrong.n go wrong.n go wrong.n go wrong.n go wrong.            // XXX If the following fails, it's probably for lack of memory,            // XXX in which case the queue will just try dynamic allocation.            (void)MPSetQueueReserve(terminationNotificationQueue, 128);        }    }}static BOOL PollNotificationQueue(Duration timeout){    OSStatus err = noErr;    void *parm1, *parm2, *parm3;        err = MPWaitOnQueue(terminationNotificationQueue,                        &parm1, &parm2, &parm3,                        timeout);    if (err == noErr) {        // then we got a notification        if ((int)parm1 == 1) {            // then it was a thread death notification, parm2 is            // the PThread pointer#ifdef DEBUG_THREADS            if (debug_mpthreads)                fprintf(stderr,"notified of %p death\n", parm2);#endif            PThread::PX_ThreadEnd(parm2);        } // else parm1 == 0 and it's just a wakeup notice    }    return err == noErr;}void PHouseKeepingThread::Main(){    PProcess & process = PProcess::Current();    SetUpTermQueue();    while (!closing) {        PTimeInterval waitTime = process.timers.Process();        Duration timeout;        if (waitTime == PMaxTimeInterval)            timeout = kDurationForever;        else {            // "Values of type Duration are 32 bits long.  They are intepreted            //  in a manner consistend with the Time Manager -- positive values            //  are in units of milliseconds, negative values are in units of            //  microseconds."              // Fortunately, PMaxTimeInterval is limited to a positive 32-bit            // number of milliseconds.            timeout = (long)waitTime.GetMilliSeconds();        }        // Block on the notification queue        (void)PollNotificationQueue(timeout);                // whether we timed out or got notified, check the signals.        process.PXCheckSignals();    }    noHousekeeper = 1;#ifdef DEBUG_THREADS    if (debug_mpthreads)        fprintf(stderr,"housekeeper exiting\n");#endif}void PProcess::Construct(){  // set the file descriptor limit to something sensible  struct rlimit rl;  PAssertOS(getrlimit(RLIMIT_NOFILE, &rl) == 0);  rl.rlim_cur = rl.rlim_max;  PAssertOS(setrlimit(RLIMIT_NOFILE, &rl) == 0);  SetUpTermQueue();  // initialise the housekeeping thread  housekeepingThread = NULL;  CommonConstruct();}PProcess::~PProcess(){  // Don't wait for housekeeper to stop if Terminate() is called from it.  if (housekeepingThread != NULL && PThread::Current() != housekeepingThread) {    housekeepingThread->SetClosing();    SignalTimerChange();    housekeepingThread->WaitForTermination();    delete housekeepingThread;    housekeepingThread = 0;  }  // XXX try to gracefully handle shutdown transient where the housekeeping  // XXX thread hasn't managed to clean up all the threads  while (PollNotificationQueue(kDurationImmediate)) ;    CommonDestruct();}PThread::PThread(){  // see InitialiseProcessThread()}void PThread::InitialiseProcessThread(){  OSStatus err        = 0;  PX_origStackSize    = 0;  autoDelete          = FALSE;  PX_threadId         = MPCurrentTaskID();  PX_suspendCount     = 0;  ::pipe(unblockPipe);  // Sadly, Mac OS MPThreads can't just initialize a block of memory into  // an MPSemaphore (XXX ought to be a CriticalRegion, but they're broken  // in Mac OS X 10.0.x!)  PX_suspendMutex = 0;  if ((err = MPCreateSemaphore(1,1,&PX_suspendMutex))      != 0) {      PAssertOS(err == 0);      throw std::bad_alloc();  }  ((PProcess *)this)->activeThreads.DisallowDeleteObjects();  ((PProcess *)this)->activeThreads.SetAt((unsigned)PX_threadId, this);}PThread::PThread(PINDEX stackSize,                 AutoDeleteFlag deletion,                 Priority /*priorityLevel*/,                 const PString & name)        : threadName(name), PX_signature(kMPThreadSig){  OSStatus err = 0;  PAssert(stackSize > 0, PInvalidParameter);  PX_origStackSize = stackSize;  autoDelete       = (deletion == AutoDeleteThread);  // Sadly, Mac OS MPThreads can't just initialize a block of memory into  // an MPSemaphore (XXX ought to be a CriticalRegion, but they're broken  // in Mac OS X 10.0.x!)  PX_suspendMutex = 0;  if ((err = MPCreateSemaphore(1,1,&PX_suspendMutex)) != 0) {      PAssert(err == 0, "MPCreateSemaphore failed");      throw std::bad_alloc();  }  ::pipe(unblockPipe);  // throw the new thread  PX_NewThread(TRUE);}PThread::~PThread(){  if (!IsTerminated())     Terminate();  ::close(unblockPipe[0]);  ::close(unblockPipe[1]);  if (PX_suspendMutex)      MPDeleteSemaphore(PX_suspendMutex);#ifdef DEBUG_THREADS  if (debug_mpthreads)      fprintf(stderr,"thread %p destructing\n", this);#endif  PX_signature = kMPDeadSig;}void PThread::PX_NewThread(BOOL startSuspended){  OSErr err;  // initialise suspend counter and create mutex  PX_suspendCount = startSuspended ? 1 : 0;  // initialise Suspend/Resume semaphore (for Mac OS X)  // XXX The MPThread manager allows for starting tasks "suspended", but I  // XXX suspect that only works if you have a debugger registered.  suspend_semaphore = new PSemaphore(0,1);  // throw the thread  SetUpTermQueue();    // create the task.#ifdef DEBUG_THREADS  if (debug_mpthreads)      fprintf(stderr,"thread %p being started\n", (void *)this);#endif  err = MPCreateTask( (TaskProc)PX_ThreadStart, (void*)this,                      65536, // stacksize                      terminationNotificationQueue,                      (void *)1,    // param 1 == "death"                      (void *)this, // param 2 == "PThread to clean up"

⌨️ 快捷键说明

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