1/***************************************************************************** 2 3 Licensed to Accellera Systems Initiative Inc. (Accellera) under one or 4 more contributor license agreements. See the NOTICE file distributed 5 with this work for additional information regarding copyright ownership. 6 Accellera licenses this file to you under the Apache License, Version 2.0 7 (the "License"); you may not use this file except in compliance with the 8 License. You may obtain a copy of the License at 9 10 http://www.apache.org/licenses/LICENSE-2.0 11 12 Unless required by applicable law or agreed to in writing, software 13 distributed under the License is distributed on an "AS IS" BASIS, 14 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 15 implied. See the License for the specific language governing 16 permissions and limitations under the License. 17 18 *****************************************************************************/ 19 20/***************************************************************************** 21 22 sc_cor_pthread.cpp -- Coroutine implementation with pthreads. 23 24 Original Author: Andy Goodrich, Forte Design Systems, 2002-11-10 25 26 CHANGE LOG APPEARS AT THE END OF THE FILE 27 *****************************************************************************/ 28 29#if !defined(_WIN32) && !defined(WIN32) && defined(SC_USE_PTHREADS) 30 31// ORDER OF THE INCLUDES AND namespace sc_core IS IMPORTANT!!! 32 33#include "sysc/kernel/sc_cor_pthread.h" 34#include "sysc/kernel/sc_simcontext.h" 35 36using namespace std; 37 38namespace sc_core { 39 40// MAKE SURE WE HAVE A NULL THAT WILL WORK: 41 42#if defined(__hpux) 43# define PTHREAD_NULL cma_c_null 44#else // !defined(__hpux) 45# define PTHREAD_NULL NULL 46#endif // !defined(__hpux) 47 48#define DEBUGF \ 49 if (0) std::cout << "sc_cor_pthread.cpp(" << __LINE__ << ") " 50 51// ---------------------------------------------------------------------------- 52// File static variables. 53// 54// (1) The thread creation mutex and the creation condition are used to 55// suspend the thread creating another one until the created thread 56// reaches its invoke_module_method. This allows us to get control of 57// thread scheduling away from the pthread package. 58// ---------------------------------------------------------------------------- 59 60static sc_cor_pthread* active_cor_p=0; // Active co-routine. 61static pthread_cond_t create_condition; // See note 1 above. 62static pthread_mutex_t create_mutex; // See note 1 above. 63static sc_cor_pthread main_cor; // Main coroutine. 64 65 66// ---------------------------------------------------------------------------- 67// CLASS : sc_cor_pthread 68// 69// Coroutine class implemented with Posix Threads. 70// ---------------------------------------------------------------------------- 71 72// constructor 73 74sc_cor_pthread::sc_cor_pthread() 75 : m_cor_fn_arg( 0 ), m_pkg_p( 0 ) 76{ 77 DEBUGF << this << ": sc_cor_pthread::sc_cor_pthread()" << std::endl; 78 pthread_cond_init( &m_pt_condition, PTHREAD_NULL ); 79 pthread_mutex_init( &m_mutex, PTHREAD_NULL ); 80} 81 82 83// destructor 84 85sc_cor_pthread::~sc_cor_pthread() 86{ 87 DEBUGF << this << ": sc_cor_pthread::~sc_cor_pthread()" << std::endl; 88 pthread_cond_destroy( &m_pt_condition); 89 pthread_mutex_destroy( &m_mutex ); 90} 91 92 93// This static method is a Posix Threads helper callback and invokes a thread 94// for the first time. It performs some synchronization and then invokes the 95// actual sc_cor helper function. 96// context_p -> thread to invoke module method of. 97// Result is 0 and ignored. 98 99void* sc_cor_pthread::invoke_module_method(void* context_p) 100{ 101 sc_cor_pthread* p = (sc_cor_pthread*)context_p; 102 DEBUGF << p << ": sc_cor_pthread::invoke_module_method()" << std::endl; 103 104 105 // SUSPEND THE THREAD SO WE CAN GAIN CONTROL FROM THE PTHREAD PACKAGE: 106 // 107 // Since pthread_create schedules each thread behind our back for its 108 // initial execution we immediately suspend a newly created thread 109 // here so we can control when its execution will occur. We also wake 110 // up the main thread which is waiting for this thread to execute to this 111 // wait point. 112 113 pthread_mutex_lock( &create_mutex ); 114 DEBUGF << p << ": child signalling main thread " << endl; 115 pthread_cond_signal( &create_condition ); 116 pthread_mutex_lock( &p->m_mutex ); 117 pthread_mutex_unlock( &create_mutex ); 118 pthread_cond_wait( &p->m_pt_condition, &p->m_mutex ); 119 pthread_mutex_unlock( &p->m_mutex ); 120 121 122 // CALL THE SYSTEMC CODE THAT WILL ACTUALLY START THE THREAD OFF: 123 124 active_cor_p = p; 125 DEBUGF << p << ": about to invoke real method " 126 << active_cor_p << std::endl; 127 (p->m_cor_fn)(p->m_cor_fn_arg); 128 129 return 0; 130} 131 132 133// ---------------------------------------------------------------------------- 134// CLASS : sc_cor_pkg_pthread 135// 136// Coroutine package class implemented with Posix Threads. 137// ---------------------------------------------------------------------------- 138 139int sc_cor_pkg_pthread::instance_count = 0; 140 141 142// constructor 143 144sc_cor_pkg_pthread::sc_cor_pkg_pthread( sc_simcontext* simc ) 145: sc_cor_pkg( simc ) 146{ 147 // initialize the current coroutine 148 if( ++ instance_count == 1 ) 149 { 150 pthread_cond_init( &create_condition, PTHREAD_NULL ); 151 pthread_mutex_init( &create_mutex, PTHREAD_NULL ); 152 assert( active_cor_p == 0 ); 153 main_cor.m_pkg_p = this; 154 DEBUGF << &main_cor << ": is main co-routine" << std::endl; 155 active_cor_p = &main_cor; 156 } 157} 158 159 160// destructor 161 162sc_cor_pkg_pthread::~sc_cor_pkg_pthread() 163{ 164 if( -- instance_count == 0 ) { 165 // cleanup the main coroutine 166 } 167} 168 169 170// create a new coroutine 171 172sc_cor* 173sc_cor_pkg_pthread::create( std::size_t stack_size, sc_cor_fn* fn, void* arg ) 174{ 175 sc_cor_pthread* cor_p = new sc_cor_pthread; 176 DEBUGF << &main_cor << ": sc_cor_pkg_pthread::create(" 177 << cor_p << ")" << std::endl; 178 179 180 // INITIALIZE OBJECT'S FIELDS FROM ARGUMENT LIST: 181 182 cor_p->m_pkg_p = this; 183 cor_p->m_cor_fn = fn; 184 cor_p->m_cor_fn_arg = arg; 185 186 187 // SET UP THREAD CREATION ATTRIBUTES: 188 // 189 // Use default values except for stack size. If stack size is non-zero 190 // set it. 191 192 pthread_attr_t attr; 193 pthread_attr_init( &attr ); 194 if ( stack_size != 0 ) 195 { 196 pthread_attr_setstacksize( &attr, stack_size ); 197 } 198 199 200 // ALLOCATE THE POSIX THREAD TO USE AND FORCE SEQUENTIAL EXECUTION: 201 // 202 // Because pthread_create causes the created thread to be executed, 203 // we need to let it run until we can block in the invoke_module_method. 204 // So we: 205 // (1) Lock the creation mutex before creating the new thread. 206 // (2) Sleep on the creation condition, which will be signalled by 207 // the newly created thread just before it goes to sleep in 208 // invoke_module_method. 209 // This scheme results in the newly created thread being dormant before 210 // the main thread continues execution. 211 212 pthread_mutex_lock( &create_mutex ); 213 DEBUGF << &main_cor << ": about to create actual thread " 214 << cor_p << std::endl; 215 if ( pthread_create( &cor_p->m_thread, &attr, 216 &sc_cor_pthread::invoke_module_method, (void*)cor_p ) ) 217 { 218 std::fprintf(stderr, "ERROR - could not create thread\n"); 219 } 220 221 DEBUGF << &main_cor << ": main thread waiting for signal from " 222 << cor_p << std::endl; 223 pthread_cond_wait( &create_condition, &create_mutex ); 224 DEBUGF << &main_cor << ": main thread signaled by " 225 << cor_p << endl; 226 pthread_attr_destroy( &attr ); 227 pthread_mutex_unlock( &create_mutex ); 228 DEBUGF << &main_cor << ": exiting sc_cor_pkg_pthread::create(" 229 << cor_p << ")" << std::endl; 230 231 return cor_p; 232} 233 234 235// yield to the next coroutine 236// 237// We don't do anything after the p_thread_cond_wait since it won't 238// happen until the thread wakes up again! 239 240void 241sc_cor_pkg_pthread::yield( sc_cor* next_cor_p ) 242{ 243 sc_cor_pthread* from_p = active_cor_p; 244 sc_cor_pthread* to_p = (sc_cor_pthread*)next_cor_p; 245 246 DEBUGF << from_p << ": switch to " << to_p << std::endl; 247 if ( to_p != from_p ) 248 { 249 pthread_mutex_lock( &to_p->m_mutex ); 250 pthread_cond_signal( &to_p->m_pt_condition ); 251 pthread_mutex_lock( &from_p->m_mutex ); 252 pthread_mutex_unlock( &to_p->m_mutex ); 253 pthread_cond_wait( &from_p->m_pt_condition, &from_p->m_mutex ); 254 pthread_mutex_unlock( &from_p->m_mutex ); 255 } 256 257 active_cor_p = from_p; // When we come out of wait make ourselves active. 258 DEBUGF << from_p << " restarting after yield to " << to_p << std::endl; 259} 260 261 262// abort the current coroutine (and resume the next coroutine) 263 264void 265sc_cor_pkg_pthread::abort( sc_cor* next_cor_p ) 266{ 267 sc_cor_pthread* n_p = (sc_cor_pthread*)next_cor_p; 268 269 DEBUGF << active_cor_p << ": aborting, switching to " << n_p << std::endl; 270 pthread_mutex_lock( &n_p->m_mutex ); 271 pthread_cond_signal( &n_p->m_pt_condition ); 272 pthread_mutex_unlock( &n_p->m_mutex ); 273} 274 275 276// get the main coroutine 277 278sc_cor* 279sc_cor_pkg_pthread::get_main() 280{ 281 return &main_cor; 282} 283 284} // namespace sc_core 285 286#endif // !defined(_WIN32) && !defined(WIN32) && defined(SC_USE_PTHREADS) 287 288 289// $Log: sc_cor_pthread.cpp,v $ 290// Revision 1.6 2011/08/30 21:51:04 acg 291// Jerome Cornet: auto processing of pthread configurations. 292// 293// Revision 1.5 2011/08/26 20:46:09 acg 294// Andy Goodrich: moved the modification log to the end of the file to 295// eliminate source line number skew when check-ins are done. 296// 297// Revision 1.4 2011/02/18 20:27:14 acg 298// Andy Goodrich: Updated Copyrights. 299// 300// Revision 1.3 2011/02/13 21:47:37 acg 301// Andy Goodrich: update copyright notice. 302// 303// Revision 1.2 2008/05/22 17:06:25 acg 304// Andy Goodrich: updated copyright notice to include 2008. 305// 306// Revision 1.1.1.1 2006/12/15 20:20:05 acg 307// SystemC 2.3 308// 309// Revision 1.3 2006/01/13 18:44:29 acg 310// Added $Log to record CVS changes into the source. 311// 312 313// Taf! 314