sc_cor_pthread.cpp

Go to the documentation of this file.
00001 /*****************************************************************************
00002 
00003   The following code is derived, directly or indirectly, from the SystemC
00004   source code Copyright (c) 1996-2006 by all Contributors.
00005   All Rights reserved.
00006 
00007   The contents of this file are subject to the restrictions and limitations
00008   set forth in the SystemC Open Source License Version 2.4 (the "License");
00009   You may not use this file except in compliance with such restrictions and
00010   limitations. You may obtain instructions on how to receive a copy of the
00011   License at http://www.systemc.org/. Software distributed by Contributors
00012   under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF
00013   ANY KIND, either express or implied. See the License for the specific
00014   language governing rights and limitations under the License.
00015 
00016  *****************************************************************************/
00017 
00018 /*****************************************************************************
00019 
00020   sc_cor_pthread.cpp -- Coroutine implementation with pthreads.
00021 
00022   Original Author: Andy Goodrich, Forte Design Systems, 2002-11-10
00023 
00024  *****************************************************************************/
00025 
00026 /*****************************************************************************
00027 
00028   MODIFICATION LOG - modifiers, enter your name, affiliation, date and
00029   changes you are making here.
00030 
00031       Name, Affiliation, Date:
00032   Description of Modification:
00033 
00034  *****************************************************************************/
00035 
00036 // $Log: sc_cor_pthread.cpp,v $
00037 // Revision 1.1.1.1  2006/12/15 20:31:36  acg
00038 // SystemC 2.2
00039 //
00040 // Revision 1.3  2006/01/13 18:44:29  acg
00041 // Added $Log to record CVS changes into the source.
00042 //
00043 
00044 #if defined(SC_USE_PTHREADS)
00045 
00046 // ORDER OF THE INCLUDES AND namespace sc_core IS IMPORTANT!!!
00047 
00048 using namespace std;
00049 
00050 #include "sysc/kernel/sc_cor_pthread.h"
00051 #include "sysc/kernel/sc_simcontext.h"
00052 
00053 namespace sc_core {
00054 
00055 // MAKE SURE WE HAVE A NULL THAT WILL WORK:
00056 
00057 #if defined(__hpux)
00058 #   define PTHREAD_NULL cma_c_null
00059 #else  // !defined(__hpux)
00060 #   define PTHREAD_NULL NULL
00061 #endif // !defined(__hpux)
00062 
00063 #define DEBUGF \
00064     if (0) std::cout << "sc_cor_pthread.cpp(" << __LINE__ << ") "
00065 
00066 // ----------------------------------------------------------------------------
00067 //  File static variables.
00068 //
00069 // (1) The thread creation mutex and the creation condition are used to
00070 //     suspend the thread creating another one until the created thread
00071 //     reaches its invoke_module_method. This allows us to get control of
00072 //     thread scheduling away from the pthread package.
00073 // ----------------------------------------------------------------------------
00074 
00075 static sc_cor_pthread* active_cor_p=0;   // Active co-routine.
00076 static pthread_cond_t  create_condition; // See note 1 above.
00077 static pthread_mutex_t create_mutex;     // See note 1 above.
00078 static sc_cor_pthread  main_cor;         // Main coroutine.
00079 
00080 
00081 // ----------------------------------------------------------------------------
00082 //  CLASS : sc_cor_pthread
00083 //
00084 //  Coroutine class implemented with Posix Threads.
00085 // ----------------------------------------------------------------------------
00086 
00087 // constructor
00088 
00089 sc_cor_pthread::sc_cor_pthread()
00090     : m_cor_fn_arg( 0 ), m_pkg_p( 0 )
00091 {
00092     DEBUGF << this << ": sc_cor_pthread::sc_cor_pthread()" << std::endl;
00093     pthread_cond_init( &m_pt_condition, PTHREAD_NULL );
00094     pthread_mutex_init( &m_mutex, PTHREAD_NULL );
00095 }
00096 
00097 
00098 // destructor
00099 
00100 sc_cor_pthread::~sc_cor_pthread()
00101 {
00102     DEBUGF << this << ": sc_cor_pthread::~sc_cor_pthread()" << std::endl;
00103     pthread_cond_destroy( &m_pt_condition);
00104     pthread_mutex_destroy( &m_mutex );
00105 }
00106 
00107 
00108 // This static method is a Posix Threads helper callback and invokes a thread
00109 // for the first time. It performs some synchronization and then invokes the
00110 // actual sc_cor helper function.
00111 //     context_p -> thread to invoke module method of.
00112 // Result is 0 and ignored.
00113 
00114 void* sc_cor_pthread::invoke_module_method(void* context_p)
00115 {
00116     sc_cor_pthread* p = (sc_cor_pthread*)context_p;
00117     DEBUGF << p << ": sc_cor_pthread::invoke_module_method()" << std::endl;
00118 
00119 
00120     // SUSPEND THE THREAD SO WE CAN GAIN CONTROL FROM THE PTHREAD PACKAGE:
00121     //
00122     // Since pthread_create schedules each thread behind our back for its
00123     // initial execution we immediately suspend a newly created thread
00124     // here so we can control when its execution will occur. We also wake
00125     // up the main thread which is waiting for this thread to execute to this
00126     // wait point.
00127 
00128     pthread_mutex_lock( &create_mutex );
00129     DEBUGF << p << ": child signalling main thread " << endl;
00130     pthread_cond_signal( &create_condition );
00131     pthread_mutex_lock( &p->m_mutex );
00132     pthread_mutex_unlock( &create_mutex );
00133     pthread_cond_wait( &p->m_pt_condition, &p->m_mutex );
00134     pthread_mutex_unlock( &p->m_mutex );
00135 
00136 
00137     // CALL THE SYSTEMC CODE THAT WILL ACTUALLY START THE THREAD OFF:
00138 
00139     active_cor_p = p;
00140     DEBUGF << p << ": about to invoke real method " 
00141        << active_cor_p << std::endl;
00142     (p->m_cor_fn)(p->m_cor_fn_arg);
00143 
00144     return 0;
00145 }
00146 
00147 
00148 // ----------------------------------------------------------------------------
00149 //  CLASS : sc_cor_pkg_pthread
00150 //
00151 //  Coroutine package class implemented with Posix Threads.
00152 // ----------------------------------------------------------------------------
00153 
00154 int sc_cor_pkg_pthread::instance_count = 0;
00155 
00156 
00157 // constructor
00158 
00159 sc_cor_pkg_pthread::sc_cor_pkg_pthread( sc_simcontext* simc )
00160 : sc_cor_pkg( simc )
00161 {
00162     // initialize the current coroutine
00163     if( ++ instance_count == 1 )
00164     {
00165         pthread_cond_init( &create_condition, PTHREAD_NULL );
00166         pthread_mutex_init( &create_mutex, PTHREAD_NULL );
00167         assert( active_cor_p == 0 );
00168         main_cor.m_pkg_p = this;
00169         DEBUGF << &main_cor << ": is main co-routine" << std::endl;
00170         active_cor_p = &main_cor;
00171     }
00172 }
00173 
00174 
00175 // destructor
00176 
00177 sc_cor_pkg_pthread::~sc_cor_pkg_pthread()
00178 {
00179     if( -- instance_count == 0 ) {
00180         // cleanup the main coroutine
00181     }
00182 }
00183 
00184 
00185 // create a new coroutine
00186 
00187 sc_cor*
00188 sc_cor_pkg_pthread::create( std::size_t stack_size, sc_cor_fn* fn, void* arg )
00189 {
00190     sc_cor_pthread* cor_p = new sc_cor_pthread;
00191     DEBUGF << &main_cor << ": sc_cor_pkg_pthread::create(" 
00192            << cor_p << ")" << std::endl;
00193 
00194 
00195     // INITIALIZE OBJECT'S FIELDS FROM ARGUMENT LIST:
00196 
00197     cor_p->m_pkg_p = this;
00198     cor_p->m_cor_fn = fn;
00199     cor_p->m_cor_fn_arg = arg;
00200 
00201 
00202     // SET UP THREAD CREATION ATTRIBUTES:
00203     //
00204     // Use default values except for stack size. If stack size is non-zero
00205     // set it.
00206 
00207     pthread_attr_t attr;
00208     pthread_attr_init( &attr ); 
00209     if ( stack_size != 0 )
00210     {
00211         pthread_attr_setstacksize( &attr, stack_size );
00212     }
00213 
00214 
00215     // ALLOCATE THE POSIX THREAD TO USE AND FORCE SEQUENTIAL EXECUTION:
00216     //
00217     // Because pthread_create causes the created thread to be executed,
00218     // we need to let it run until we can block in the invoke_module_method.
00219     // So we:
00220     //   (1) Lock the creation mutex before creating the new thread.
00221     //   (2) Sleep on the creation condition, which will be signalled by
00222     //       the newly created thread just before it goes to sleep in
00223     //       invoke_module_method.
00224     // This scheme results in the newly created thread being dormant before
00225     // the main thread continues execution.
00226 
00227     pthread_mutex_lock( &create_mutex );
00228     DEBUGF << &main_cor << ": about to create actual thread " 
00229            << cor_p << std::endl;
00230     if ( pthread_create( &cor_p->m_thread, &attr,
00231              &sc_cor_pthread::invoke_module_method, (void*)cor_p ) )
00232     {
00233         std::fprintf(stderr, "ERROR - could not create thread\n");
00234     }
00235 
00236     DEBUGF << &main_cor << ": main thread waiting for signal from " 
00237            << cor_p << std::endl;
00238     pthread_cond_wait( &create_condition, &create_mutex );
00239     DEBUGF << &main_cor << ": main thread signaled by " 
00240            << cor_p << endl;
00241     pthread_attr_destroy( &attr ); 
00242     pthread_mutex_unlock( &create_mutex );
00243     DEBUGF << &main_cor << ": exiting sc_cor_pkg_pthread::create(" 
00244            << cor_p << ")" << std::endl;
00245 
00246     return cor_p;
00247 }
00248 
00249 
00250 // yield to the next coroutine
00251 //
00252 // We don't do anything after the p_thread_cond_wait since it won't
00253 // happen until the thread wakes up again!
00254 
00255 void
00256 sc_cor_pkg_pthread::yield( sc_cor* next_cor_p )
00257 {
00258     sc_cor_pthread* from_p = active_cor_p;
00259     sc_cor_pthread* to_p = (sc_cor_pthread*)next_cor_p;
00260 
00261     DEBUGF << from_p << ": switch to " << to_p << std::endl;
00262     if ( to_p != from_p )
00263     {
00264         pthread_mutex_lock( &to_p->m_mutex );
00265         pthread_cond_signal( &to_p->m_pt_condition );
00266         pthread_mutex_lock( &from_p->m_mutex );
00267         pthread_mutex_unlock( &to_p->m_mutex );
00268         pthread_cond_wait( &from_p->m_pt_condition, &from_p->m_mutex );
00269         pthread_mutex_unlock( &from_p->m_mutex );
00270     }
00271 
00272     active_cor_p = from_p; // When we come out of wait make ourselves active.
00273     DEBUGF << from_p << " restarting after yield to " << to_p << std::endl;
00274 }
00275 
00276 
00277 // abort the current coroutine (and resume the next coroutine)
00278 
00279 void
00280 sc_cor_pkg_pthread::abort( sc_cor* next_cor_p )
00281 {
00282     sc_cor_pthread* n_p = (sc_cor_pthread*)next_cor_p;
00283 
00284     DEBUGF << active_cor_p << ": aborting, switching to " << n_p << std::endl;
00285     pthread_mutex_lock( &n_p->m_mutex );
00286     pthread_cond_signal( &n_p->m_pt_condition );
00287     pthread_mutex_unlock( &n_p->m_mutex );
00288 }
00289 
00290 
00291 // get the main coroutine
00292 
00293 sc_cor*
00294 sc_cor_pkg_pthread::get_main()
00295 {
00296     return &main_cor;
00297 }
00298 
00299 } // namespace sc_core
00300 
00301 #endif // defined(SC_USE_PTHREADS)
00302 
00303 
00304 // Taf!

Generated on Wed Jan 21 15:32:09 2009 for SystemC by  doxygen 1.5.5