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
00031
00032
00033
00034
00035
00036
00037
00038
00039 #include <errno.h>
00040
00041 #include "config.h"
00042 #include "Thread.h"
00043 #include "SpinLock.h"
00044
00045 #include "../debug/DebugUtils.h"
00046 #include "../debug/Log.h"
00047 #include "../util/CString.h"
00048
00049 #if GOOGLE_PROFILE_ENABLED
00050 #include <google/profiler.h>
00051 #endif
00052
00053 namespace oasys {
00054
00055 #ifdef __win32__
00056 __declspec(thread) Thread* Thread::current_thread_ = 0;
00057 #else
00058 bool Thread::signals_inited_ = false;
00059 sigset_t Thread::interrupt_sigset_;
00060 #endif
00061
00062 bool Thread::start_barrier_enabled_ = false;
00063 std::vector<Thread*> Thread::threads_in_barrier_;
00064
00065 const int Thread::max_live_threads_;
00066 Thread* Thread::all_threads_[max_live_threads_];
00067 SpinLock g_all_threads_lock_;
00068 SpinLock* Thread::all_threads_lock_ = &g_all_threads_lock_;
00069
00070
00071 void
00072 Thread::activate_start_barrier()
00073 {
00074 start_barrier_enabled_ = true;
00075 log_debug("/thread", "activating thread creation barrier");
00076 }
00077
00078
00079 void
00080 Thread::release_start_barrier()
00081 {
00082 start_barrier_enabled_ = false;
00083
00084 log_debug("/thread",
00085 "releasing thread creation barrier -- %zu queued threads",
00086 threads_in_barrier_.size());
00087
00088 for (size_t i = 0; i < threads_in_barrier_.size(); ++i)
00089 {
00090 Thread* thr = threads_in_barrier_[i];
00091 thr->start();
00092 }
00093
00094 threads_in_barrier_.clear();
00095 }
00096
00097
00098 bool
00099 Thread::id_equal(ThreadId_t a, ThreadId_t b)
00100 {
00101 #ifdef __win32__
00102
00103 return a == b;
00104 #else
00105 return pthread_equal(a, b);
00106 #endif
00107 }
00108
00109
00110 Thread::Thread(const char* name, int flags)
00111 : flags_(flags)
00112 {
00113 if ((flags & CREATE_JOINABLE) && (flags & DELETE_ON_EXIT)) {
00114 flags &= ~DELETE_ON_EXIT;
00115 }
00116
00117 #ifdef __win32__
00118 if (flags & CREATE_JOINABLE) {
00119 join_event_ = CreateEvent(0, TRUE, FALSE, 0);
00120 ASSERT(join_event_ != 0);
00121 } else {
00122 join_event_ = 0;
00123 }
00124 #endif //__win32__
00125 cstring_copy(name_, 64, name);
00126 thread_id_ = 0;
00127 }
00128
00129
00130 Thread::~Thread()
00131 {
00132 #ifdef __win32__
00133 if (join_event_ != 0) {
00134 CloseHandle(join_event_);
00135 }
00136 #endif //__win32__
00137 }
00138
00139
00140 void
00141 Thread::start()
00142 {
00143 #ifndef __win32__
00144
00145
00146 if (!signals_inited_)
00147 {
00148 sigemptyset(&interrupt_sigset_);
00149 sigaddset(&interrupt_sigset_, INTERRUPT_SIG);
00150 signal(INTERRUPT_SIG, interrupt_signal);
00151 siginterrupt(INTERRUPT_SIG, 1);
00152 signals_inited_ = true;
00153 }
00154
00155 #endif
00156
00157
00158 if (start_barrier_enabled_)
00159 {
00160 log_debug("/thread", "delaying start of thread %p due to barrier",
00161 this);
00162 threads_in_barrier_.push_back(this);
00163 return;
00164 }
00165
00166 log_debug("/thread", "starting thread %p", this);
00167
00168 #ifdef __win32__
00169
00170 DWORD thread_dword_id;
00171 HANDLE h_thread = CreateThread(0,
00172 0,
00173 Thread::pre_thread_run,
00174 this,
00175
00176
00177 CREATE_SUSPENDED,
00178 &thread_dword_id);
00179
00180 ASSERT(h_thread != 0);
00181 thread_id_ = thread_dword_id;
00182
00183
00184 ResumeThread(h_thread);
00185 #else
00186
00187
00188
00189 int ntries = 0;
00190 while (pthread_create(&thread_id_, 0, Thread::pre_thread_run, this) != 0)
00191 {
00192 if (++ntries == 10000) {
00193 PANIC("maximum thread creation attempts");
00194 #ifdef OASYS_DEBUG_MEMORY_ENABLED
00195 DbgMemInfo::debug_dump();
00196 #endif
00197 }
00198
00199 log_err("/thread", "error in thread_id_create: %s, retrying",
00200 strerror(errno));
00201 }
00202
00203
00204
00205 if (! (flags_ & CREATE_JOINABLE))
00206 {
00207 pthread_detach(thread_id_);
00208 }
00209
00210 #endif // __win32__
00211 }
00212
00213
00214 void
00215 Thread::join()
00216 {
00217 if (! (flags_ & CREATE_JOINABLE))
00218 {
00219 PANIC("tried to join a thread that isn't joinable -- "
00220 "need CREATE_JOINABLE flag");
00221 }
00222
00223 #ifdef __win32__
00224 ASSERT(join_event_ != 0);
00225 DWORD ret = WaitForSingleObject(join_event_, INFINITE);
00226 (void)ret;
00227 ASSERT(ret != WAIT_FAILED);
00228 #else
00229 void* ignored;
00230 int err;
00231 if ((err = pthread_join(thread_id_, &ignored)) != 0)
00232 {
00233 PANIC("error in pthread_join: %s", strerror(err));
00234 }
00235 #endif
00236 }
00237
00238
00239 void
00240 Thread::kill(int sig)
00241 {
00242 #ifdef __win32__
00243 (void)sig;
00244 NOTIMPLEMENTED;
00245 #else
00246 if (pthread_kill(thread_id_, sig) != 0) {
00247 PANIC("error in pthread_kill: %s", strerror(errno));
00248 }
00249 #endif
00250 }
00251
00252
00253 void
00254 Thread::interrupt()
00255 {
00256 #ifdef __win32__
00257 NOTIMPLEMENTED;
00258 #else
00259 log_debug("/thread", "interrupting thread %p", this);
00260 kill(INTERRUPT_SIG);
00261 #endif
00262 }
00263
00264
00265 void
00266 Thread::set_interruptable(bool interruptable)
00267 {
00268 #ifdef __win32__
00269 (void)interruptable;
00270 NOTIMPLEMENTED;
00271 #else
00272 ASSERT(Thread::current() == thread_id_);
00273
00274 int block = (interruptable ? SIG_UNBLOCK : SIG_BLOCK);
00275 if (pthread_sigmask(block, &interrupt_sigset_, NULL) != 0) {
00276 PANIC("error in thread_id_sigmask");
00277 }
00278 #endif
00279 }
00280
00281
00282
00283 #ifdef __win32__
00284 DWORD WINAPI
00285 #else
00286 void*
00287 #endif
00288 Thread::pre_thread_run(void* t)
00289 {
00290 Thread* thr = static_cast<Thread*>(t);
00291
00292 #ifdef __win32__
00293 current_thread_ = thr;
00294 #endif
00295
00296 ThreadId_t thread_id = Thread::current();
00297 thr->thread_run(thr->name_, thread_id);
00298
00299 return 0;
00300 }
00301
00302
00303 void
00304 Thread::interrupt_signal(int sig)
00305 {
00306 (void)sig;
00307 }
00308
00309
00310 void
00311 Thread::thread_run(const char* thread_name, ThreadId_t thread_id)
00312 {
00313
00314
00315
00316
00317
00318 (void)thread_name;
00319
00320 #if GOOGLE_PROFILE_ENABLED
00321 ProfilerRegisterThread();
00322 #endif
00323
00324 all_threads_lock_->lock("thread startup");
00325 for (int i = 0; i < max_live_threads_; ++i) {
00326 if (all_threads_[i] == NULL) {
00327 all_threads_[i] = this;
00328 break;
00329 }
00330 }
00331 all_threads_lock_->unlock();
00332
00333 #ifndef __win32__
00334
00335
00336
00337
00338
00339
00340
00341
00342 thread_id_ = thread_id;
00343 set_interruptable((flags_ & INTERRUPTABLE));
00344 #endif
00345
00346 flags_ |= STARTED;
00347 flags_ &= ~STOPPED;
00348 flags_ &= ~SHOULD_STOP;
00349
00350 try
00351 {
00352 run();
00353 }
00354 catch (...)
00355 {
00356 PANIC("unexpected exception caught from Thread::run");
00357 }
00358
00359 flags_ |= STOPPED;
00360
00361 #ifdef __win32__
00362 if (join_event_) {
00363 SetEvent(join_event_);
00364 }
00365 #endif //__win32__
00366
00367 all_threads_lock_->lock("thread startup");
00368 for (int i = 0; i < max_live_threads_; ++i) {
00369 if (all_threads_[i] == this) {
00370 all_threads_[i] = NULL;
00371 break;
00372 }
00373 }
00374 all_threads_lock_->unlock();
00375
00376 if (flags_ & DELETE_ON_EXIT)
00377 {
00378 delete this;
00379 }
00380
00381 #ifdef __win32__
00382
00383
00384
00385 return;
00386
00387 #else
00388
00389 pthread_exit(0);
00390 NOTREACHED;
00391
00392 #endif
00393 }
00394
00395 }