00001 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ 00002 /* 00003 * Copyright (c) 2008 INRIA 00004 * 00005 * This program is free software; you can redistribute it and/or modify 00006 * it under the terms of the GNU General Public License version 2 as 00007 * published by the Free Software Foundation; 00008 * 00009 * This program is distributed in the hope that it will be useful, 00010 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00012 * GNU General Public License for more details. 00013 * 00014 * You should have received a copy of the GNU General Public License 00015 * along with this program; if not, write to the Free Software 00016 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 00017 * 00018 * Author: Mathieu Lacage <mathieu.lacage.inria.fr> 00019 */ 00020 00021 #include <pthread.h> 00022 #include <string.h> 00023 #include <signal.h> 00024 #include "fatal-error.h" 00025 #include "system-thread.h" 00026 #include "log.h" 00027 00028 NS_LOG_COMPONENT_DEFINE ("SystemThread"); 00029 00030 namespace ns3 { 00031 00032 // 00033 // Private implementation class for the SystemThread class. The deal is 00034 // that we export the SystemThread class to the user. The header just 00035 // declares a class and its members. There is a forward declaration for 00036 // a private implementation class there and a member declaration. Thus 00037 // there is no knowledge of the implementation in the exported header. 00038 // 00039 // We provide an implementation class for each operating system. This is 00040 // the Unix implementation of the SystemThread. 00041 // 00042 // In order to use the SystemThread, you will include "system-thread.h" and 00043 // get the implementation by linking unix-system-thread.cc (if you are running 00044 // a Posix system). 00045 // 00046 class SystemThreadImpl 00047 { 00048 public: 00049 SystemThreadImpl (Callback<void> callback); 00050 00051 void Start (void); 00052 void Join (void); 00053 void Shutdown (void); 00054 bool Break (void); 00055 00056 private: 00057 static void *DoRun (void *arg); 00058 Callback<void> m_callback; 00059 pthread_t m_thread; 00060 bool m_break; 00061 void * m_ret; 00062 }; 00063 00064 SystemThreadImpl::SystemThreadImpl (Callback<void> callback) 00065 : m_callback (callback) 00066 { 00067 NS_LOG_FUNCTION_NOARGS (); 00068 // Make sure we have a SIGALRM handler which does not terminate 00069 // our process. 00070 struct sigaction act; 00071 act.sa_flags = 0; 00072 sigemptyset (&act.sa_mask); 00073 act.sa_handler = SIG_IGN; 00074 sigaction (SIGALRM, &act, 0); 00075 } 00076 00077 void 00078 SystemThreadImpl::Start (void) 00079 { 00080 NS_LOG_FUNCTION_NOARGS (); 00081 00082 int rc = pthread_create (&m_thread, NULL, &SystemThreadImpl::DoRun, 00083 (void *)this); 00084 00085 if (rc) 00086 { 00087 NS_FATAL_ERROR ("pthread_create failed: " << rc << "=\"" << 00088 strerror(rc) << "\"."); 00089 } 00090 } 00091 00092 void 00093 SystemThreadImpl::Join (void) 00094 { 00095 NS_LOG_FUNCTION_NOARGS (); 00096 00097 void *thread_return; 00098 int rc = pthread_join (m_thread, &thread_return); 00099 if (rc) 00100 { 00101 NS_FATAL_ERROR ("pthread_join failed: " << rc << "=\"" << 00102 strerror(rc) << "\"."); 00103 } 00104 } 00105 00106 void 00107 SystemThreadImpl::Shutdown (void) 00108 { 00109 NS_LOG_FUNCTION_NOARGS (); 00110 00111 m_break = true; 00112 00113 // send a SIGALRM signal on the target thread to make sure that it 00114 // will unblock. 00115 pthread_kill (m_thread, SIGALRM); 00116 } 00117 00118 bool 00119 SystemThreadImpl::Break (void) 00120 { 00121 NS_LOG_FUNCTION_NOARGS (); 00122 00123 return m_break; 00124 } 00125 00126 void * 00127 SystemThreadImpl::DoRun (void *arg) 00128 { 00129 NS_LOG_FUNCTION_NOARGS (); 00130 00131 SystemThreadImpl *self = static_cast<SystemThreadImpl *> (arg); 00132 self->m_callback (); 00133 00134 return 0; 00135 } 00136 00137 // 00138 // Remember that we just export the delcaration of the SystemThread class to 00139 // the user. There is no code to implement the SystemThread methods. We 00140 // have to do that here. We just vector the calls to our implementation 00141 // class above. 00142 // 00143 SystemThread::SystemThread (Callback<void> callback) 00144 : m_impl (new SystemThreadImpl (callback)), 00145 m_count (1) 00146 { 00147 NS_LOG_FUNCTION_NOARGS (); 00148 } 00149 00150 SystemThread::~SystemThread() 00151 { 00152 NS_LOG_FUNCTION_NOARGS (); 00153 delete m_impl; 00154 } 00155 00156 void 00157 SystemThread::Start (void) 00158 { 00159 NS_LOG_FUNCTION_NOARGS (); 00160 m_impl->Start (); 00161 } 00162 00163 void 00164 SystemThread::Join (void) 00165 { 00166 NS_LOG_FUNCTION_NOARGS (); 00167 m_impl->Join (); 00168 } 00169 00170 void 00171 SystemThread::Shutdown (void) 00172 { 00173 NS_LOG_FUNCTION_NOARGS (); 00174 m_impl->Shutdown (); 00175 } 00176 00177 bool 00178 SystemThread::Break (void) 00179 { 00180 NS_LOG_FUNCTION_NOARGS (); 00181 return m_impl->Break (); 00182 } 00183 00184 } // namespace ns3