Thread.cc

Go to the documentation of this file.
00001 /*
00002  *    Copyright 2004-2006 Intel Corporation
00003  * 
00004  *    Licensed under the Apache License, Version 2.0 (the "License");
00005  *    you may not use this file except in compliance with the License.
00006  *    You may obtain a copy of the License at
00007  * 
00008  *        http://www.apache.org/licenses/LICENSE-2.0
00009  * 
00010  *    Unless required by applicable law or agreed to in writing, software
00011  *    distributed under the License is distributed on an "AS IS" BASIS,
00012  *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00013  *    See the License for the specific language governing permissions and
00014  *    limitations under the License.
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     // XXX/bowei - check if comparing handles for equality is ok
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     // if this is the first thread, set up signals
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     // check if the creation barrier is enabled
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, // Security attributes
00151                                    0, // default stack size
00152                                    Thread::pre_thread_run, // thread function
00153                                    this,
00154                                    // start suspended to fix some state in
00155                                    // the Thread* class before it starts running
00156                                    CREATE_SUSPENDED,       
00157                                    &thread_dword_id);
00158     
00159     ASSERT(h_thread != 0);
00160     thread_id_ = thread_dword_id;
00161 
00162     // Fix the handle on the thread
00163     ResumeThread(h_thread);
00164 #else 
00165 
00166     // If the thread create fails, we retry once every 100ms for up to
00167     // a minute before panic'ing. This allows a temporary resource
00168     // shortage (typically memory) to clean itself up before dying
00169     // completely.
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     // since in most cases we want detached threads, users must
00186     // explicitly request for them to be joinable
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; // XXX/bowei - get rid of me
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      * The only reason we pass the name to thread_run is to make it
00297      * appear in the gdb backtrace to more easily identify the actual
00298      * thread.
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      * There's a potential race between the starting of the new thread
00318      * and the storing of the thread id in the thread_id_ member
00319      * variable, so we can't trust that it's been written by our
00320      * spawner. So we re-write it here to make sure that it's valid
00321      * for the new thread (specifically for set_interruptable's
00322      * assertion.
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     // Make sure C++ cleanup is called, which does not occur if we
00366     // call ExitThread().
00367     return;
00368 
00369 #else
00370 
00371     pthread_exit(0);
00372     NOTREACHED;
00373 
00374 #endif
00375 }
00376 
00377 } // namespace oasys

Generated on Thu Jun 7 12:54:30 2007 for DTN Reference Implementation by  doxygen 1.5.1