00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030 #ifdef __linux__
00031
00032 #define _XOPEN_SOURCE 500
00033 #endif
00034 #include "pthreadcompat.h"
00035 #include <errno.h>
00036 #include <signal.h>
00037 #include <stdio.h>
00038 #include <sys/time.h>
00039 #include "Basics.H"
00040 #include "ThreadStart.H"
00041
00042
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
00052
00053
00054
00055
00056 static void report (int code, char *who) throw ()
00057 {
00058
00059 cerr << "pthread_" << who << " failed: "
00060 << Basics::errno_Text(code)
00061 << " (errno: " << code << ")" << endl;
00062 abort();
00063 }
00064
00065
00066
00067
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 { }
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
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 { }
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
00153
00154
00155
00156 static const size_t g_min_guardsize = 8192;
00157
00158 Basics::thread_attr::thread_attr() throw ()
00159 {
00160 int code = pthread_attr_init( &(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( &(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( &(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
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( &(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
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( &(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), &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( &(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), &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( &(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), &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( &(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), &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
00282
00283
00284 struct sched_param my_sched_param;
00285 int code = pthread_attr_getschedparam( &(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( &(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( &(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
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
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
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, &result);
00357 if (code != 0) report(code, "join");
00358 return result;
00359 }
00360
00361 void Basics::thread::get_sched_param( int &policy,
00362 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
00375
00376
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
00391 static Basics::mutex dummyMu;
00392 static Basics::cond dummyCond;
00393
00394 void Basics::thread::pause(int secs, int usecs) throw ()
00395 {
00396
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
00406 struct timespec tv =
00407 { goal.tv_sec, 1000 * (goal.tv_usec) };
00408
00409
00410 while (tv.tv_nsec > NSEC_PER_SEC) {
00411 tv.tv_nsec -= NSEC_PER_SEC;
00412 tv.tv_sec++;
00413 }
00414
00415 do {
00416
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
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 }