(file) Return to Thread.cpp CVS log (file) (dir) Up to [Pegasus] / pegasus / src / Pegasus / Common

Diff for /pegasus/src/Pegasus/Common/Thread.cpp between version 1.1.2.10 and 1.29.4.6

version 1.1.2.10, 2001/10/29 11:25:22 version 1.29.4.6, 2003/03/26 14:40:57
Line 1 
Line 1 
 //%///////////////////////////////////////////////////////////////////////////// //%/////////////////////////////////////////////////////////////////////////////
 // //
 // Copyright (c) 2000, 2001 The Open group, BMC Software, Tivoli Systems, IBM  // Copyright (c) 2000, 2001, 2002 BMC Software, Hewlett-Packard Company, IBM,
   // The Open Group, Tivoli Systems
 // //
 // Permission is hereby granted, free of charge, to any person obtaining a copy // Permission is hereby granted, free of charge, to any person obtaining a copy
 // of this software and associated documentation files (the "Software"), to // of this software and associated documentation files (the "Software"), to
Line 22 
Line 23 
 // //
 // Author: Mike Day (mdday@us.ibm.com) // Author: Mike Day (mdday@us.ibm.com)
 // //
 // Modified By:  // Modified By: Rudy Schuet (rudy.schuet@compaq.com) 11/12/01
   //              added nsk platform support
 // //
 //%///////////////////////////////////////////////////////////////////////////// //%/////////////////////////////////////////////////////////////////////////////
  
 #include "Thread.h" #include "Thread.h"
 #include <Pegasus/Common/IPC.h> #include <Pegasus/Common/IPC.h>
   #include <Pegasus/Common/Tracer.h>
  
 #if defined(PEGASUS_OS_TYPE_WINDOWS) #if defined(PEGASUS_OS_TYPE_WINDOWS)
 # include "ThreadWindows.cpp" # include "ThreadWindows.cpp"
 #elif defined(PEGASUS_OS_TYPE_UNIX) #elif defined(PEGASUS_OS_TYPE_UNIX)
 # include "ThreadUnix.cpp" # include "ThreadUnix.cpp"
   #elif defined(PEGASUS_OS_TYPE_NSK)
   # include "ThreadNsk.cpp"
 #else #else
 # error "Unsupported platform" # error "Unsupported platform"
 #endif #endif
Line 56 
Line 61 
     {     {
         _cleanup.insert_first(cu);         _cleanup.insert_first(cu);
     }     }
     catch(IPCException& e)      catch(IPCException&)
     {     {
         delete cu;         delete cu;
         throw;         throw;
Line 71 
Line 76 
     {     {
         cu = _cleanup.remove_first() ;         cu = _cleanup.remove_first() ;
     }     }
     catch(IPCException& e)      catch(IPCException&)
     {     {
         PEGASUS_ASSERT(0);         PEGASUS_ASSERT(0);
     }     }
Line 83 
Line 88 
 #endif #endif
  
  
 //thread_data *Thread::put_tsd(Sint8 *key, void (*delete_func)(void *), Uint32 size, void *value) throw(IPCException)  //thread_data *Thread::put_tsd(const Sint8 *key, void (*delete_func)(void *), Uint32 size, void *value) throw(IPCException)
  
  
 #ifndef PEGASUS_THREAD_EXIT_NATIVE #ifndef PEGASUS_THREAD_EXIT_NATIVE
Line 96 
Line 101 
        {        {
            cleanup_pop(true);            cleanup_pop(true);
        }        }
        catch(IPCException& e)         catch(IPCException&)
        {        {
           PEGASUS_ASSERT(0);           PEGASUS_ASSERT(0);
           break;           break;
Line 104 
Line 109 
    }    }
    _exit_code = exit_code;    _exit_code = exit_code;
    exit_thread(exit_code);    exit_thread(exit_code);
      _handle.thid = 0;
 } }
  
  
 #endif #endif
  
   DQueue<ThreadPool> ThreadPool::_pools(true);
   
   
   void ThreadPool::kill_idle_threads(void)
   {
      static struct timeval now, last = {0, 0};
   
      pegasus_gettimeofday(&now);
      if(now.tv_sec - last.tv_sec > 5)
      {
         _pools.lock();
         ThreadPool *p = _pools.next(0);
         while(p != 0)
         {
            try
            {
               p->kill_dead_threads();
            }
            catch(...)
            {
            }
            p = _pools.next(p);
         }
         _pools.unlock();
         pegasus_gettimeofday(&last);
      }
   }
   
  
 ThreadPool::ThreadPool(Sint16 initial_size, ThreadPool::ThreadPool(Sint16 initial_size,
                        Sint16 max,                         const Sint8 *key,
                        Sint16 min,                        Sint16 min,
                        Sint8 *key)                         Sint16 max,
                          struct timeval & alloc_wait,
                          struct timeval & dealloc_wait,
                          struct timeval & deadlock_detect)
    : _max_threads(max), _min_threads(min),    : _max_threads(max), _min_threads(min),
      _current_threads(0), _waiters(initial_size),       _current_threads(0),
      _pool_sem(0), _pool(true), _running(true),       _pool(true), _running(true),
      _dying(0)       _dead(true), _dying(0)
 {  {
    _allocate_wait.tv_sec = 1;     _allocate_wait.tv_sec = alloc_wait.tv_sec;
    _allocate_wait.tv_usec = 0;     _allocate_wait.tv_usec = alloc_wait.tv_usec;
    _deallocate_wait.tv_sec = 30;     _deallocate_wait.tv_sec = dealloc_wait.tv_sec;
    _deallocate_wait.tv_usec = 0;     _deallocate_wait.tv_usec = dealloc_wait.tv_usec;
    _deadlock_detect.tv_sec = 60;     _deadlock_detect.tv_sec = deadlock_detect.tv_sec;
    _deadlock_detect.tv_usec = 0;     _deadlock_detect.tv_usec = deadlock_detect.tv_usec;
    memset(_key, 0x00, 17);    memset(_key, 0x00, 17);
    if(key != 0)    if(key != 0)
       strncpy(_key, key, 16);       strncpy(_key, key, 16);
    if(_max_threads < initial_size)     if(_max_threads > 0 && _max_threads < initial_size)
       _max_threads = initial_size;       _max_threads = initial_size;
    if(_min_threads > initial_size)    if(_min_threads > initial_size)
       _min_threads = initial_size;       _min_threads = initial_size;
Line 138 
Line 175 
    {    {
       _link_pool(_init_thread());       _link_pool(_init_thread());
    }    }
      _pools.insert_last(this);
   
 } }
  
   
   
 ThreadPool::~ThreadPool(void) ThreadPool::~ThreadPool(void)
 { {
      try
      {
         _pools.remove(this);
    _dying++;    _dying++;
    Thread *th = _pool.remove_first();        Thread *th = 0;
         th = _pool.remove_first();
    while(th != 0)    while(th != 0)
    {    {
            Semaphore *sleep_sem = (Semaphore *)th->reference_tsd("sleep sem");
   
            if(sleep_sem == 0)
            {
               th->dereference_tsd();
               throw NullPointer();
            }
   
            sleep_sem->signal();
            sleep_sem->signal();
            th->dereference_tsd();
       // signal the thread's sleep semaphore       // signal the thread's sleep semaphore
       th->cancel();       th->cancel();
       th->join();       th->join();
Line 153 
Line 209 
       delete th;       delete th;
       th = _pool.remove_first();       th = _pool.remove_first();
    }    }
   
         th = _running.remove_first();
         while(th != 0)
         {
            // signal the thread's sleep semaphore
            th->cancel();
            th->join();
            th->empty_tsd();
            delete th;
            th = _running.remove_first();
         }
   
         th = _dead.remove_first();
         while(th != 0)
         {
            // signal the thread's sleep semaphore
            th->cancel();
            th->join();
            th->empty_tsd();
            delete th;
            th = _dead.remove_first();
         }
      }
      catch(...)
      {
      }
 } }
  
 // make this static to the class // make this static to the class
 PEGASUS_THREAD_RETURN PEGASUS_THREAD_CDECL ThreadPool::_loop(void *parm) PEGASUS_THREAD_RETURN PEGASUS_THREAD_CDECL ThreadPool::_loop(void *parm)
 { {
      PEG_METHOD_ENTER(TRC_THREAD, "ThreadPool::_loop");
   
    Thread *myself = (Thread *)parm;    Thread *myself = (Thread *)parm;
    if(myself == 0)    if(myself == 0)
      {
         PEG_METHOD_EXIT();
       throw NullPointer();       throw NullPointer();
      }
    ThreadPool *pool = (ThreadPool *)myself->get_parm();    ThreadPool *pool = (ThreadPool *)myself->get_parm();
    if(pool == 0 )    if(pool == 0 )
      {
         PEG_METHOD_EXIT();
       throw NullPointer();       throw NullPointer();
    Semaphore *sleep_sem;     }
    struct timeval *deadlock_timer;     Semaphore *sleep_sem = 0;
      Semaphore *blocking_sem = 0;
   
      struct timeval *deadlock_timer = 0;
  
    try    try
    {    {
Line 174 
Line 266 
       deadlock_timer = (struct timeval *)myself->reference_tsd("deadlock timer");       deadlock_timer = (struct timeval *)myself->reference_tsd("deadlock timer");
       myself->dereference_tsd();       myself->dereference_tsd();
    }    }
    catch(IPCException & e)     catch(IPCException &)
      {
         PEG_METHOD_EXIT();
         myself->exit_self(0);
      }
      catch(...)
    {    {
         PEG_METHOD_EXIT();
       myself->exit_self(0);       myself->exit_self(0);
    }    }
   
    if(sleep_sem == 0 || deadlock_timer == 0)    if(sleep_sem == 0 || deadlock_timer == 0)
      {
         PEG_METHOD_EXIT();
       throw NullPointer();       throw NullPointer();
      }
  
    while(pool->_dying < 1)    while(pool->_dying < 1)
    {    {
       myself->test_cancel();  
       sleep_sem->wait();       sleep_sem->wait();
   
       // when we awaken we reside on the running queue, not the pool queue       // when we awaken we reside on the running queue, not the pool queue
       myself->test_cancel();        if(pool->_dying > 0)
       gettimeofday(deadlock_timer, NULL);           break;
  
       PEGASUS_THREAD_RETURN (PEGASUS_THREAD_CDECL *_work)(void *);        PEGASUS_THREAD_RETURN (PEGASUS_THREAD_CDECL *_work)(void *) = 0;
       void *parm;        void *parm = 0;
  
       try       try
       {       {
Line 199 
Line 301 
          myself->dereference_tsd();          myself->dereference_tsd();
          parm = myself->reference_tsd("work parm");          parm = myself->reference_tsd("work parm");
          myself->dereference_tsd();          myself->dereference_tsd();
            blocking_sem = (Semaphore *)myself->reference_tsd("blocking sem");
            myself->dereference_tsd();
   
       }       }
       catch(IPCException & e)        catch(IPCException &)
       {       {
            PEG_METHOD_EXIT();
          myself->exit_self(0);          myself->exit_self(0);
       }       }
  
       if(_work == 0)       if(_work == 0)
         {
            PEG_METHOD_EXIT();
          throw NullPointer();          throw NullPointer();
         }
   
         if(_work ==
            (PEGASUS_THREAD_RETURN (PEGASUS_THREAD_CDECL *)(void *)) &_undertaker)
         {
       _work(parm);       _work(parm);
         }
   
         gettimeofday(deadlock_timer, NULL);
         try
         {
            _work(parm);
         }
         catch(...)
         {
            gettimeofday(deadlock_timer, NULL);
         }
         gettimeofday(deadlock_timer, NULL);
         if( blocking_sem != 0 )
            blocking_sem->signal();
  
       // put myself back onto the available list       // put myself back onto the available list
       try       try
Line 215 
Line 342 
          pool->_running.remove((void *)myself);          pool->_running.remove((void *)myself);
          pool->_link_pool(myself);          pool->_link_pool(myself);
       }       }
       catch(IPCException & e)        catch(IPCException &)
       {       {
            PEG_METHOD_EXIT();
          myself->exit_self(0);          myself->exit_self(0);
       }       }
    }    }
      // wait to be awakend by the thread pool destructor
      sleep_sem->wait();
      myself->test_cancel();
   
      PEG_METHOD_EXIT();
    myself->exit_self(0);    myself->exit_self(0);
    return((PEGASUS_THREAD_RETURN)0);    return((PEGASUS_THREAD_RETURN)0);
 } }
  
   
 void ThreadPool::allocate_and_awaken(void *parm, void ThreadPool::allocate_and_awaken(void *parm,
                                      PEGASUS_THREAD_RETURN \                                      PEGASUS_THREAD_RETURN \
                                      (PEGASUS_THREAD_CDECL *work)(void *))                                       (PEGASUS_THREAD_CDECL *work)(void *),
                                        Semaphore *blocking)
   
    throw(IPCException)    throw(IPCException)
 { {
      PEG_METHOD_ENTER(TRC_THREAD, "ThreadPool::allocate_and_awaken");
    struct timeval start;    struct timeval start;
    gettimeofday(&start, NULL);    gettimeofday(&start, NULL);
  
    Thread *th = _pool.remove_first();    Thread *th = _pool.remove_first();
  
    while (th == 0 && _dying < 1)  
    {  
       try  // we couldn't get a free thread from the pool  
       {  
          // wait for the right interval and try again          // wait for the right interval and try again
          while(th == 0 && _dying < 1)          while(th == 0 && _dying < 1)
          {          {
             _check_deadlock(&start);             _check_deadlock(&start);
             Uint32 interval = _allocate_wait.tv_sec * 1000;  
             if(_allocate_wait.tv_usec > 0)        if(_max_threads == 0 || _current_threads < _max_threads)
                interval += (_deallocate_wait.tv_usec / 1000);  
             // will throw a timeout if no thread comes free  
             _pool_sem.time_wait(interval);  
             th = _pool.remove_first();  
          }  
       }  
       catch(TimeOut & to)  
       {  
          if(_current_threads < _max_threads)  
          {          {
             th = _init_thread();             th = _init_thread();
             break;           continue;
          }          }
         pegasus_yield();
         th = _pool.remove_first();
       }       }
       // will throw a Deadlock Exception before falling out of the loop  
       _check_deadlock(&start);  
    } // while th == null  
  
    if(_dying < 1)    if(_dying < 1)
    {    {
       // initialize the thread data with the work function and parameters       // initialize the thread data with the work function and parameters
       th->remove_tsd("work func");        Tracer::trace(TRC_THREAD, Tracer::LEVEL4,
             "Initializing thread with work function and parameters: parm = %p",
             parm);
   
         th->delete_tsd("work func");
       th->put_tsd("work func", NULL,       th->put_tsd("work func", NULL,
                   sizeof( PEGASUS_THREAD_RETURN (PEGASUS_THREAD_CDECL *)(void *)),                   sizeof( PEGASUS_THREAD_RETURN (PEGASUS_THREAD_CDECL *)(void *)),
                   (void *)work);                   (void *)work);
       th->remove_tsd("work parm");        th->delete_tsd("work parm");
       th->put_tsd("work parm", NULL, sizeof(void *), parm);       th->put_tsd("work parm", NULL, sizeof(void *), parm);
         th->delete_tsd("blocking sem");
         if(blocking != 0 )
            th->put_tsd("blocking sem", NULL, sizeof(Semaphore *), blocking);
  
       // put the thread on the running list       // put the thread on the running list
       _running.insert_first(th);       _running.insert_first(th);
  
       // signal the thread's sleep semaphore to awaken it       // signal the thread's sleep semaphore to awaken it
       Semaphore *sleep_sem = (Semaphore *)th->reference_tsd("sleep sem");       Semaphore *sleep_sem = (Semaphore *)th->reference_tsd("sleep sem");
   
       if(sleep_sem == 0)       if(sleep_sem == 0)
         {
            th->dereference_tsd();
            PEG_METHOD_EXIT();
          throw NullPointer();          throw NullPointer();
         }
         Tracer::trace(TRC_THREAD, Tracer::LEVEL4, "Signal thread to awaken");
       sleep_sem->signal();       sleep_sem->signal();
         th->dereference_tsd();
    }    }
    else    else
       _pool.insert_first(th);       _pool.insert_first(th);
   
      PEG_METHOD_EXIT();
 } }
  
 // caller is responsible for only calling this routine during slack periods // caller is responsible for only calling this routine during slack periods
 // but should call it at least once per _deadlock_detect with the running q // but should call it at least once per _deadlock_detect with the running q
 // and at least once per _deallocate_wait for the pool q // and at least once per _deallocate_wait for the pool q
  
 void ThreadPool::_kill_dead_threads(DQueue<Thread> *q, Boolean (*check)(struct timeval *))  Uint32 ThreadPool::kill_dead_threads(void)
    throw(IPCException)    throw(IPCException)
 { {
    struct timeval now;    struct timeval now;
    gettimeofday(&now, NULL);    gettimeofday(&now, NULL);
      Uint32 bodies = 0;
  
    DQueue<Thread> dead ;     // first go thread the dead q and clean it up as much as possible
      while(_dead.count() > 0)
      {
         PEGASUS_STD(cout) << "ThreadPool:: removing and joining dead thread" << PEGASUS_STD(endl);
         Thread *dead = _dead.remove_first();
         if(dead == 0)
            throw NullPointer();
         dead->join();
         delete dead;
      }
  
      DQueue<Thread> * map[2] =
         {
            &_pool, &_running
         };
   
   
      DQueue<Thread> *q = 0;
      int i = 0;
      AtomicInt needed(0);
   
   
      for( ; i < 2; i++)
      {
         q = map[i];
    if(q->count() > 0 )    if(q->count() > 0 )
    {    {
       try       try
       {       {
          q->try_lock();          q->try_lock();
       }       }
       catch(AlreadyLocked & a)           catch(...)
       {       {
          return;              return bodies;
       }       }
  
       Thread *context = 0;  
       struct timeval dt = { 0, 0 };       struct timeval dt = { 0, 0 };
       struct timeval *dtp;       struct timeval *dtp;
       Thread *th = q->next(context);           Thread *th = 0;
            th = q->next(th);
       while (th != 0 )       while (th != 0 )
       {       {
          try          try
          {          {
             dtp = (struct timeval *)th->try_reference_tsd("deadlock timer");             dtp = (struct timeval *)th->try_reference_tsd("deadlock timer");
          }          }
          catch(AlreadyLocked & a)              catch(...)
          {          {
             context = th;                 q->unlock();
             th = q->next(context);                 return bodies;
             continue;  
          }          }
  
          if(dtp != 0)          if(dtp != 0)
          {          {
             memcpy(&dt, dtp, sizeof(struct timeval));             memcpy(&dt, dtp, sizeof(struct timeval));
   
          }          }
          th->dereference_tsd();          th->dereference_tsd();
          if( true == check(&dt))              struct timeval deadlock_timeout;
               Boolean too_long;
               if( i == 0)
          {          {
             th = q->remove_no_lock((void *)th);                 too_long = check_time(&dt, get_deallocate_wait(&deadlock_timeout));
               }
               else
               {
                  too_long = check_time(&dt, get_deadlock_detect(&deadlock_timeout));
               }
  
             if(th != 0)              if( true == too_long)
             {             {
                dead.insert_first(th);                 // if we are deallocating from the pool, escape if we are
                th = 0;                 // down to the minimum thread count
                  _current_threads--;
                  if( _current_threads.value() < (Uint32)_min_threads )
                  {
                     if( i == 0)
                     {
                        _current_threads++;
                        th = q->next(th);
                        continue;
             }             }
                     else
                     {
                        // we are killing a hung thread and we will drop below the
                        // minimum. create another thread to make up for the one
                        // we are about to kill
                        needed++;
          }          }
          context = th;  
          th = q->next(context);  
       }       }
   
                  th = q->remove_no_lock((void *)th);
   
                  if(th != 0)
                  {
                     if( i == 0 )
                     {
                        th->delete_tsd("work func");
                        th->put_tsd("work func", NULL,
                                    sizeof( PEGASUS_THREAD_RETURN (PEGASUS_THREAD_CDECL *)(void *)),
                                    (void *)&_undertaker);
                        th->delete_tsd("work parm");
                        th->put_tsd("work parm", NULL, sizeof(void *), th);
   
                        // signal the thread's sleep semaphore to awaken it
                        Semaphore *sleep_sem = (Semaphore *)th->reference_tsd("sleep sem");
   
                        if(sleep_sem == 0)
                        {
       q->unlock();       q->unlock();
                           th->dereference_tsd();
                           throw NullPointer();
    }    }
  
    if(dead.count())                       bodies++;
    {                       th->dereference_tsd();
       Thread *th = dead.remove_first();                       _dead.insert_first(th);
       while(th != 0)                       sleep_sem->signal();
                        th = 0;
                     }
                     else
       {       {
                        // deadlocked threads
                        PEGASUS_STD(cout) << "Killing a deadlocked thread" << PEGASUS_STD(endl);
          th->cancel();          th->cancel();
          th->join();  
          delete th;          delete th;
          th = dead.remove_first();  
       }       }
    }    }
    return;              }
               th = q->next(th);
               pegasus_sleep(1);
            }
            q->unlock();
            while (needed.value() > 0)
            {
               _link_pool(_init_thread());
               needed--;
               pegasus_sleep(0);
            }
         }
      }
       return bodies;
 } }
  
 Boolean ThreadPool::_check_time(struct timeval *start, struct timeval *interval)  
   Boolean ThreadPool::check_time(struct timeval *start, struct timeval *interval)
 { {
    struct timeval now;     // never time out if the interval is zero
      if(interval && interval->tv_sec == 0 && interval->tv_usec == 0)
         return false;
   
      struct timeval now, finish, remaining;
      Uint32 usec;
    gettimeofday(&now, NULL);    gettimeofday(&now, NULL);
    if( (now.tv_sec - start->tv_sec) > interval->tv_sec ||  
        (((now.tv_sec - start->tv_sec) == interval->tv_sec) &&     finish.tv_sec = start->tv_sec + interval->tv_sec;
         ((now.tv_usec - start->tv_usec) >= interval->tv_usec ) ) )     usec = start->tv_usec + interval->tv_usec;
      finish.tv_sec += (usec / 1000000);
      usec %= 1000000;
      finish.tv_usec = usec;
   
      if ( timeval_subtract(&remaining, &finish, &now) )
       return true;       return true;
    else    else
       return false;       return false;
 } }
  
   PEGASUS_THREAD_RETURN ThreadPool::_undertaker( void *parm )
   {
      exit_thread((PEGASUS_THREAD_RETURN)1);
      return (PEGASUS_THREAD_RETURN)1;
   }
   
   
 void ThreadPool::_sleep_sem_del(void *p) void ThreadPool::_sleep_sem_del(void *p)
 { {
    if(p != 0)    if(p != 0)
Line 382 
Line 616 
    }    }
 } }
  
 inline void ThreadPool::_check_deadlock(struct timeval *start) throw(Deadlock)   void ThreadPool::_check_deadlock(struct timeval *start) throw(Deadlock)
 { {
    if (true == _check_time(start, &_deadlock_detect))     if (true == check_time(start, &_deadlock_detect))
       throw Deadlock(pegasus_thread_self());       throw Deadlock(pegasus_thread_self());
    return;    return;
 } }
  
  
 inline Boolean ThreadPool::_check_deadlock_no_throw(struct timeval *start)   Boolean ThreadPool::_check_deadlock_no_throw(struct timeval *start)
 { {
    return(_check_time(start, &_deadlock_detect));     return(check_time(start, &_deadlock_detect));
 } }
  
 inline Boolean ThreadPool::_check_dealloc(struct timeval *start)   Boolean ThreadPool::_check_dealloc(struct timeval *start)
 { {
    return(_check_time(start, &_deallocate_wait));     return(check_time(start, &_deallocate_wait));
 } }
  
 inline Thread *ThreadPool::_init_thread(void) throw(IPCException)   Thread *ThreadPool::_init_thread(void) throw(IPCException)
 { {
    Thread *th = (Thread *) new Thread(&_loop, this, false);     Thread *th = (Thread *) new Thread(_loop, this, false);
    // allocate a sleep semaphore and pass it in the thread context    // allocate a sleep semaphore and pass it in the thread context
    // initial count is zero, loop function will sleep until    // initial count is zero, loop function will sleep until
    // we signal the semaphore    // we signal the semaphore
    Semaphore *sleep_sem = (Semaphore *) new Semaphore(0);    Semaphore *sleep_sem = (Semaphore *) new Semaphore(0);
    th->put_tsd("sleep sem", &_sleep_sem_del, sizeof(Semaphore), (void *)sleep_sem);    th->put_tsd("sleep sem", &_sleep_sem_del, sizeof(Semaphore), (void *)sleep_sem);
   
    struct timeval *dldt = (struct timeval *) ::operator new(sizeof(struct timeval));    struct timeval *dldt = (struct timeval *) ::operator new(sizeof(struct timeval));
      pegasus_gettimeofday(dldt);
   
    th->put_tsd("deadlock timer", thread_data::default_delete, sizeof(struct timeval), (void *)dldt);    th->put_tsd("deadlock timer", thread_data::default_delete, sizeof(struct timeval), (void *)dldt);
    // thread will enter _loop(void *) and sleep on sleep_sem until we signal it    // thread will enter _loop(void *) and sleep on sleep_sem until we signal it
    th->run();    th->run();
    _current_threads++;    _current_threads++;
      pegasus_yield();
   
    return th;    return th;
 } }
  
 inline void ThreadPool::_link_pool(Thread *th) throw(IPCException)   void ThreadPool::_link_pool(Thread *th) throw(IPCException)
 { {
    if(th == 0)    if(th == 0)
       throw NullPointer();       throw NullPointer();
    _pool.insert_first(th);    _pool.insert_first(th);
    _pool_sem.signal();  
 } }
  
  
   
 PEGASUS_NAMESPACE_END PEGASUS_NAMESPACE_END
  


Legend:
Removed from v.1.1.2.10  
changed lines
  Added in v.1.29.4.6

No CVS admin address has been configured
Powered by
ViewCVS 0.9.2