Main Page | Namespace List | Class Hierarchy | Class List | Directories | File List | Namespace Members | Class Members | File Members

Thread.C

Go to the documentation of this file.
00001 // Copyright (C) 2001, Compaq Computer Corporation
00002 
00003 // This file is part of Vesta.
00004 
00005 // Vesta is free software; you can redistribute it and/or
00006 // modify it under the terms of the GNU Lesser General Public
00007 // License as published by the Free Software Foundation; either
00008 // version 2.1 of the License, or (at your option) any later version.
00009 
00010 // Vesta is distributed in the hope that it will be useful,
00011 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00012 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013 // Lesser General Public License for more details.
00014 
00015 // You should have received a copy of the GNU Lesser General Public
00016 // License along with Vesta; if not, write to the Free Software
00017 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00018 
00019 // Last modified on Fri Jul 22 15:16:27 EDT 2005 by irina.furman@intel.com
00020 //      modified on Sun May 22 21:35:39 EDT 2005 by ken@xorian.net
00021 //      modified on Fri Jul 27 18:05:21 PDT 2001 by mann   
00022 //      modified on Wed Dec 13 11:08:53 PST 2000 by yuanyu 
00023 //      modified on Fri Aug 28 09:09:00 PDT 1998 by heydon
00024 //      modified on Fri Feb  3 14:41:31 PST 1995 by levin
00025 
00026 //  ***************************************
00027 //  *  Simplified threads implementation  *
00028 //  ***************************************
00029 
00030 #ifdef __linux__
00031 // On Linux, we need this #define to get pthread_attr_setguardsize
00032 #define _XOPEN_SOURCE 500
00033 #endif
00034 #include "pthreadcompat.h"
00035 #include <errno.h>
00036 #include <signal.h>
00037 #include <stdio.h> // just to get sprintf
00038 #include <sys/time.h>
00039 #include "Basics.H"
00040 #include "ThreadStart.H"
00041 
00042 // Some platforms (Tru64) define this, and some (Linux) don't.
00043 #ifndef NSEC_PER_SEC
00044 #define NSEC_PER_SEC (1000000000)
00045 #endif
00046 
00047 using std::cerr;
00048 using std::endl;
00049 
00050 //  ***********************************
00051 //  *  Simplified pthread operations  *
00052 //  ***********************************
00053 
00054 //  Utility failure reporting procedure
00055 
00056 static void report (int code, char *who) throw ()
00057 {
00058   // Convenient visibility in the debugger :-)
00059   cerr << "pthread_" << who << " failed: "
00060        << Basics::errno_Text(code)
00061        << " (errno: " << code << ")" << endl;
00062   abort();
00063 }
00064 
00065 
00066 //  **************************
00067 //  *  Mutex implementation  *
00068 //  **************************
00069 
00070 Basics::mutex::mutex() throw ()
00071 {
00072   int code = pthread_mutex_init(&(this->m), (pthread_mutexattr_t *)NULL);
00073   if (code != 0) report(code, "mutex_init");  
00074 }
00075 
00076 Basics::mutex::mutex(int type) throw ()
00077 {
00078   pthread_mutexattr_t attr;
00079   int code = pthread_mutexattr_init(&attr);
00080   if(code != 0) report(code, "mutexattr_init");
00081   code = pthread_mutexattr_settype(&attr, type); 
00082   if(code != 0) report(code, "mutexattr_settype");
00083 
00084   code = pthread_mutex_init(&(this->m), &attr);
00085   if(code != 0) report(code, "mutex_init");  
00086   
00087   code = pthread_mutexattr_destroy(&attr);
00088   if(code != 0) report(code, "mutexattr_destroy");
00089 }
00090 
00091 Basics::mutex::~mutex() throw ()
00092 { /* SKIP */ }
00093 
00094 void Basics::mutex::lock() throw ()
00095 {
00096   int code = pthread_mutex_lock(&(this->m));
00097   if (code != 0) report(code, "mutex_lock");
00098 }
00099 
00100 void Basics::mutex::unlock() throw ()
00101 {
00102   int code = pthread_mutex_unlock(&(this->m));
00103   if (code != 0) report(code, "mutex_unlock");
00104 }
00105 
00106 
00107 //  ***************************************
00108 //  *  Condition variable implementation  *
00109 //  ***************************************
00110 
00111 Basics::cond::cond() throw ()
00112 {
00113   int code = pthread_cond_init(&(this->c), (pthread_condattr_t *)NULL);
00114   if (code != 0) report(code, "cond_init");  
00115 }
00116 
00117 Basics::cond::~cond() throw ()
00118 { /* SKIP */ }
00119 
00120 void Basics::cond::wait(mutex &m) throw ()
00121 {
00122   int code = pthread_cond_wait(&(this->c), &(m.m));
00123   if (code != 0) report(code, "cond_wait");
00124 }
00125 
00126 int Basics::cond::timedwait(mutex &m, struct timespec *abstime) throw ()
00127 {
00128   int code = pthread_cond_timedwait(&(this->c), &(m.m), abstime);
00129 #ifdef _PTHREAD_D4_ // from "pthreadcompat.h"
00130   if (code != 0 && errno != 0 && errno != EAGAIN)
00131       report(errno, "cond_timedwait");
00132 #else
00133   if (code != 0 && code != ETIMEDOUT)
00134       report(code, "cond_timedwait");
00135 #endif
00136   return code;
00137 }
00138 
00139 void Basics::cond::signal() throw ()
00140 {
00141   int code = pthread_cond_signal(&(this->c));
00142   if (code != 0) report(code, "cond_signal");
00143 }
00144 
00145 void Basics::cond::broadcast() throw ()
00146 {
00147   int code = pthread_cond_broadcast(&(this->c));
00148   if (code != 0) report(code, "cond_broadcast");
00149 }
00150 
00151 //  ******************************************
00152 //  *  Thread attributeclass implementation  *
00153 //  ******************************************
00154 
00155 // Default from the old thread::fork_inner
00156 static const size_t g_min_guardsize = 8192;
00157 
00158 Basics::thread_attr::thread_attr() throw ()
00159 {
00160   int code = pthread_attr_init(/*OUT*/ &(this->attr));
00161   if (code != 0) report(code, "attr_init");
00162 
00163   if(get_guardsize() < g_min_guardsize)
00164     set_guardsize(g_min_guardsize);
00165 }
00166 
00167 Basics::thread_attr::thread_attr(size_t stacksize) throw ()
00168 {
00169   int code = pthread_attr_init(/*OUT*/ &(this->attr));
00170   if (code != 0) report(code, "attr_init");
00171 
00172   if(get_guardsize() < g_min_guardsize)
00173     set_guardsize(g_min_guardsize);
00174 
00175   set_stacksize(stacksize);
00176 }
00177 
00178 Basics::thread_attr::thread_attr(const thread_attr &other) throw()
00179 {
00180   int code = pthread_attr_init(/*OUT*/ &(this->attr));
00181   if (code != 0) report(code, "attr_init");
00182 
00183   set_guardsize(other.get_guardsize());
00184   set_stacksize(other.get_stacksize());
00185   
00186 #if defined (_POSIX_THREAD_PRIORITY_SCHEDULING)
00187   set_schedpolicy(other.get_schedpolicy());
00188 # if !defined(VALGRIND_SUPPORT)
00189   // valgrind chokes on the inheritsched pthread calls
00190   set_inheritsched(other.get_inheritsched());
00191 # endif
00192   set_sched_priority(other.get_sched_priority());
00193 #endif
00194 }
00195 
00196 Basics::thread_attr::~thread_attr() throw ()
00197 {
00198   int code = pthread_attr_destroy(/*OUT*/ &(this->attr));
00199   if (code != 0) report(code, "attr_destroy");
00200 }
00201 
00202 Basics::thread_attr &Basics::thread_attr::operator=(const Basics::thread_attr &other) throw()
00203 {
00204   set_guardsize(other.get_guardsize());
00205   set_stacksize(other.get_stacksize());
00206   
00207 #if defined (_POSIX_THREAD_PRIORITY_SCHEDULING)
00208   set_schedpolicy(other.get_schedpolicy());
00209 # if !defined(VALGRIND_SUPPORT)
00210   // valgrind chokes on the inheritsched pthread calls
00211   set_inheritsched(other.get_inheritsched());
00212 # endif
00213   set_sched_priority(other.get_sched_priority());
00214 #endif
00215 
00216   return *this;
00217 }
00218 
00219 void Basics::thread_attr::set_guardsize(size_t guardsize) throw()
00220 {
00221   int code = pthread_attr_setguardsize(/*INOUT*/ &(this->attr),
00222                                        max(guardsize, g_min_guardsize));
00223   if (code != 0) report(code, "attr_setguardsize");
00224 }
00225 
00226 size_t Basics::thread_attr::get_guardsize() const throw()
00227 {
00228   size_t result;
00229   int code = pthread_attr_getguardsize(&(this->attr), /*OUT*/ &result);
00230   if (code != 0) report(code, "attr_getguardsize");
00231   return result;
00232 }
00233 
00234 void Basics::thread_attr::set_stacksize(size_t stacksize) throw()
00235 {
00236   int code = pthread_attr_setstacksize(/*INOUT*/ &(this->attr),
00237                                        max(stacksize, PTHREAD_STACK_MIN));
00238   if (code != 0) report(code, "attr_setstacksize");
00239 }
00240 
00241 size_t Basics::thread_attr::get_stacksize() const throw()
00242 {
00243   size_t result;
00244   int code = pthread_attr_getstacksize(&(this->attr), /*OUT*/ &result);
00245   if (code != 0) report(code, "attr_getstacksize");
00246   return result;
00247 }
00248 
00249 #if defined (_POSIX_THREAD_PRIORITY_SCHEDULING)
00250 void Basics::thread_attr::set_schedpolicy(int policy) throw()
00251 {
00252   int code = pthread_attr_setschedpolicy(/*INOUT*/ &(this->attr), policy);
00253   if (code != 0) report(code, "attr_schedpolicy");
00254 }
00255 
00256 int Basics::thread_attr::get_schedpolicy() const throw()
00257 {
00258   int result;
00259   int code = pthread_attr_getschedpolicy(&(this->attr), /*OUT*/ &result);
00260   if (code != 0) report(code, "attr_getschedpolicy");
00261   return result;
00262 }
00263 
00264 void Basics::thread_attr::set_inheritsched(int inheritsched) throw()
00265 {
00266   int code = pthread_attr_setinheritsched(/*INOUT*/ &(this->attr),
00267                                           inheritsched);
00268   if (code != 0) report(code, "attr_setinheritsched");
00269 }
00270 
00271 int Basics::thread_attr::get_inheritsched() const throw()
00272 {
00273   int result;
00274   int code = pthread_attr_getinheritsched(&(this->attr), /*OUT*/ &result);
00275   if (code != 0) report(code, "attr_getinheritsched");
00276   return result;
00277 }
00278 
00279 void Basics::thread_attr::set_sched_priority(int sched_priority) throw()
00280 {
00281   // The only defined member of struct sched_param is sched_priority,
00282   // but there may be others, so we first get it, then set the
00283   // sched_param member, then set it.
00284   struct sched_param my_sched_param;
00285   int code = pthread_attr_getschedparam(/*INOUT*/ &(this->attr),
00286                                         &my_sched_param);
00287   if (code != 0) report(code, "attr_getschedparam");
00288   my_sched_param.sched_priority = sched_priority;
00289   code =  pthread_attr_setschedparam(/*INOUT*/ &(this->attr),
00290                                      &my_sched_param);
00291   if (code != 0) report(code, "attr_setschedparam");
00292 }
00293 
00294 int Basics::thread_attr::get_sched_priority() const throw()
00295 {
00296   struct sched_param my_sched_param;
00297   int code = pthread_attr_getschedparam(/*INOUT*/ &(this->attr),
00298                                         &my_sched_param);
00299   if (code != 0) report(code, "attr_getschedparam");
00300   return my_sched_param.sched_priority;
00301 }
00302 #endif
00303 
00304 //  *********************************
00305 //  *  Thread class implementation  *
00306 //  *********************************
00307 
00308 void Basics::thread::fork_inner(StartRoutine proc, void *arg,
00309                                 const thread_attr &attr)
00310   throw ()
00311 {
00312   ForkArgs *forkArgs = NEW(ForkArgs);
00313   forkArgs->proc = proc;
00314   forkArgs->arg = arg;
00315   forkArgs->started = false;
00316 
00317 #if defined(__linux__) && defined(GPROF_SUPPORT)
00318   // gprof support (see comment in ThreadStart.H)
00319   getitimer(ITIMER_PROF, &(forkArgs->itimer));
00320 #endif
00321 
00322   int code = pthread_create(&(this->t), &(attr.attr),
00323     ThreadStart_Callback, (void *)forkArgs);
00324   if (code != 0) {
00325     report(code, "create");
00326   }
00327 
00328   // wait until child is running
00329   ThreadStart_WaitForChild(forkArgs);
00330 }
00331 
00332 void Basics::thread::fork(StartRoutine proc, void *arg,
00333                           const thread_attr &attr)
00334   throw ()
00335 {
00336   fork_inner(proc, arg, attr);
00337 }
00338 
00339 void Basics::thread::detach() throw ()
00340 {
00341   int code = pthread_detach(this->t);
00342   if (code != 0) report(code, "detach");
00343 }
00344 
00345 void Basics::thread::fork_and_detach(StartRoutine proc, void *arg,
00346                                      const Basics::thread_attr &attr)
00347   throw ()
00348 {
00349   this->fork(proc, arg, attr);
00350   this->detach();
00351 }
00352 
00353 void *Basics::thread::join() throw ()
00354 {
00355   void *result;
00356   int code = pthread_join(this->t, /*OUT*/ &result);
00357   if (code != 0) report(code, "join");
00358   return result;
00359 }
00360 
00361 void Basics::thread::get_sched_param(/*OUT*/ int &policy,
00362                                      /*OUT*/ int &sched_priority) throw()
00363 {
00364   struct sched_param my_sched_param;
00365   int code = pthread_getschedparam(this->t,
00366                                    &policy,
00367                                    &my_sched_param);
00368   if (code != 0) report(code, "getschedparam");
00369   sched_priority = my_sched_param.sched_priority;
00370 }
00371 
00372 void Basics::thread::set_sched_param(int policy, int sched_priority) throw()
00373 {
00374   // The only defined member of struct sched_param is sched_priority,
00375   // but there may be others, so we first get it, then set the
00376   // sched_param member, then set it.
00377   int old_policy;
00378   struct sched_param my_sched_param;
00379   int code = pthread_getschedparam(this->t,
00380                                    &old_policy,
00381                                    &my_sched_param);
00382   if (code != 0) report(code, "getschedparam");
00383   my_sched_param.sched_priority = sched_priority;
00384   code = pthread_setschedparam(this->t,
00385                                policy,
00386                                &my_sched_param);
00387   if (code != 0) report(code, "setschedparam");
00388 }
00389 
00390 // dummy mutex and condition variable for "thread::pause"
00391 static Basics::mutex dummyMu;
00392 static Basics::cond dummyCond;
00393 
00394 void Basics::thread::pause(int secs, int usecs) throw ()
00395 {
00396     // get the current time
00397     int code;
00398     struct timeval now;
00399     if ((code = gettimeofday(&now, NULL)) != 0) {
00400         report(code, "gettimeofday");
00401     }
00402 
00403     struct timeval goal = { now.tv_sec + secs, now.tv_usec + usecs };
00404 
00405     // add "secs", "usecs" to current time
00406     struct timespec tv =
00407       { goal.tv_sec, 1000 * (goal.tv_usec) };
00408 
00409     // handle overflow in "tv.tv_nsec" field
00410     while (tv.tv_nsec > NSEC_PER_SEC) {
00411         tv.tv_nsec -= NSEC_PER_SEC;
00412         tv.tv_sec++;
00413     }
00414 
00415     do {
00416       // wait -- since nothing signals this condition var, it will time out
00417       dummyMu.lock();
00418       (void) dummyCond.timedwait(dummyMu, &tv);
00419       dummyMu.unlock();
00420 
00421       if ((code = gettimeofday(&now, NULL)) != 0) {
00422         report(code, "gettimeofday");
00423       }
00424 
00425       // Loop to handle early wakeups.
00426     } while(now.tv_sec < goal.tv_sec ||
00427             now.tv_sec == goal.tv_sec && now.tv_usec < goal.tv_usec);
00428 }
00429 
00430 Basics::thread Basics::thread::self() throw()
00431 {
00432   return thread(pthread_self());
00433 }

Generated on Mon May 8 00:48:29 2006 for Vesta by  doxygen 1.4.2