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