112027Sjungma@eit.uni-kl.de/***************************************************************************** 212027Sjungma@eit.uni-kl.de 312027Sjungma@eit.uni-kl.de Licensed to Accellera Systems Initiative Inc. (Accellera) under one or 412027Sjungma@eit.uni-kl.de more contributor license agreements. See the NOTICE file distributed 512027Sjungma@eit.uni-kl.de with this work for additional information regarding copyright ownership. 612027Sjungma@eit.uni-kl.de Accellera licenses this file to you under the Apache License, Version 2.0 712027Sjungma@eit.uni-kl.de (the "License"); you may not use this file except in compliance with the 812027Sjungma@eit.uni-kl.de License. You may obtain a copy of the License at 912027Sjungma@eit.uni-kl.de 1012027Sjungma@eit.uni-kl.de http://www.apache.org/licenses/LICENSE-2.0 1112027Sjungma@eit.uni-kl.de 1212027Sjungma@eit.uni-kl.de Unless required by applicable law or agreed to in writing, software 1312027Sjungma@eit.uni-kl.de distributed under the License is distributed on an "AS IS" BASIS, 1412027Sjungma@eit.uni-kl.de WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 1512027Sjungma@eit.uni-kl.de implied. See the License for the specific language governing 1612027Sjungma@eit.uni-kl.de permissions and limitations under the License. 1712027Sjungma@eit.uni-kl.de 1812027Sjungma@eit.uni-kl.de *****************************************************************************/ 1912027Sjungma@eit.uni-kl.de 2012027Sjungma@eit.uni-kl.de/***************************************************************************** 2112027Sjungma@eit.uni-kl.de 2212027Sjungma@eit.uni-kl.de sc_cor_pthread.cpp -- Coroutine implementation with pthreads. 2312027Sjungma@eit.uni-kl.de 2412027Sjungma@eit.uni-kl.de Original Author: Andy Goodrich, Forte Design Systems, 2002-11-10 2512027Sjungma@eit.uni-kl.de 2612027Sjungma@eit.uni-kl.de CHANGE LOG APPEARS AT THE END OF THE FILE 2712027Sjungma@eit.uni-kl.de *****************************************************************************/ 2812027Sjungma@eit.uni-kl.de 2912027Sjungma@eit.uni-kl.de#if !defined(_WIN32) && !defined(WIN32) && defined(SC_USE_PTHREADS) 3012027Sjungma@eit.uni-kl.de 3112027Sjungma@eit.uni-kl.de// ORDER OF THE INCLUDES AND namespace sc_core IS IMPORTANT!!! 3212027Sjungma@eit.uni-kl.de 3312027Sjungma@eit.uni-kl.de#include "sysc/kernel/sc_cor_pthread.h" 3412027Sjungma@eit.uni-kl.de#include "sysc/kernel/sc_simcontext.h" 3512027Sjungma@eit.uni-kl.de 3612027Sjungma@eit.uni-kl.deusing namespace std; 3712027Sjungma@eit.uni-kl.de 3812027Sjungma@eit.uni-kl.denamespace sc_core { 3912027Sjungma@eit.uni-kl.de 4012027Sjungma@eit.uni-kl.de// MAKE SURE WE HAVE A NULL THAT WILL WORK: 4112027Sjungma@eit.uni-kl.de 4212027Sjungma@eit.uni-kl.de#if defined(__hpux) 4312027Sjungma@eit.uni-kl.de# define PTHREAD_NULL cma_c_null 4412027Sjungma@eit.uni-kl.de#else // !defined(__hpux) 4512027Sjungma@eit.uni-kl.de# define PTHREAD_NULL NULL 4612027Sjungma@eit.uni-kl.de#endif // !defined(__hpux) 4712027Sjungma@eit.uni-kl.de 4812027Sjungma@eit.uni-kl.de#define DEBUGF \ 4912027Sjungma@eit.uni-kl.de if (0) std::cout << "sc_cor_pthread.cpp(" << __LINE__ << ") " 5012027Sjungma@eit.uni-kl.de 5112027Sjungma@eit.uni-kl.de// ---------------------------------------------------------------------------- 5212027Sjungma@eit.uni-kl.de// File static variables. 5312027Sjungma@eit.uni-kl.de// 5412027Sjungma@eit.uni-kl.de// (1) The thread creation mutex and the creation condition are used to 5512027Sjungma@eit.uni-kl.de// suspend the thread creating another one until the created thread 5612027Sjungma@eit.uni-kl.de// reaches its invoke_module_method. This allows us to get control of 5712027Sjungma@eit.uni-kl.de// thread scheduling away from the pthread package. 5812027Sjungma@eit.uni-kl.de// ---------------------------------------------------------------------------- 5912027Sjungma@eit.uni-kl.de 6012027Sjungma@eit.uni-kl.destatic sc_cor_pthread* active_cor_p=0; // Active co-routine. 6112027Sjungma@eit.uni-kl.destatic pthread_cond_t create_condition; // See note 1 above. 6212027Sjungma@eit.uni-kl.destatic pthread_mutex_t create_mutex; // See note 1 above. 6312027Sjungma@eit.uni-kl.destatic sc_cor_pthread main_cor; // Main coroutine. 6412027Sjungma@eit.uni-kl.de 6512027Sjungma@eit.uni-kl.de 6612027Sjungma@eit.uni-kl.de// ---------------------------------------------------------------------------- 6712027Sjungma@eit.uni-kl.de// CLASS : sc_cor_pthread 6812027Sjungma@eit.uni-kl.de// 6912027Sjungma@eit.uni-kl.de// Coroutine class implemented with Posix Threads. 7012027Sjungma@eit.uni-kl.de// ---------------------------------------------------------------------------- 7112027Sjungma@eit.uni-kl.de 7212027Sjungma@eit.uni-kl.de// constructor 7312027Sjungma@eit.uni-kl.de 7412027Sjungma@eit.uni-kl.desc_cor_pthread::sc_cor_pthread() 7512027Sjungma@eit.uni-kl.de : m_cor_fn_arg( 0 ), m_pkg_p( 0 ) 7612027Sjungma@eit.uni-kl.de{ 7712027Sjungma@eit.uni-kl.de DEBUGF << this << ": sc_cor_pthread::sc_cor_pthread()" << std::endl; 7812027Sjungma@eit.uni-kl.de pthread_cond_init( &m_pt_condition, PTHREAD_NULL ); 7912027Sjungma@eit.uni-kl.de pthread_mutex_init( &m_mutex, PTHREAD_NULL ); 8012027Sjungma@eit.uni-kl.de} 8112027Sjungma@eit.uni-kl.de 8212027Sjungma@eit.uni-kl.de 8312027Sjungma@eit.uni-kl.de// destructor 8412027Sjungma@eit.uni-kl.de 8512027Sjungma@eit.uni-kl.desc_cor_pthread::~sc_cor_pthread() 8612027Sjungma@eit.uni-kl.de{ 8712027Sjungma@eit.uni-kl.de DEBUGF << this << ": sc_cor_pthread::~sc_cor_pthread()" << std::endl; 8812027Sjungma@eit.uni-kl.de pthread_cond_destroy( &m_pt_condition); 8912027Sjungma@eit.uni-kl.de pthread_mutex_destroy( &m_mutex ); 9012027Sjungma@eit.uni-kl.de} 9112027Sjungma@eit.uni-kl.de 9212027Sjungma@eit.uni-kl.de 9312027Sjungma@eit.uni-kl.de// This static method is a Posix Threads helper callback and invokes a thread 9412027Sjungma@eit.uni-kl.de// for the first time. It performs some synchronization and then invokes the 9512027Sjungma@eit.uni-kl.de// actual sc_cor helper function. 9612027Sjungma@eit.uni-kl.de// context_p -> thread to invoke module method of. 9712027Sjungma@eit.uni-kl.de// Result is 0 and ignored. 9812027Sjungma@eit.uni-kl.de 9912027Sjungma@eit.uni-kl.devoid* sc_cor_pthread::invoke_module_method(void* context_p) 10012027Sjungma@eit.uni-kl.de{ 10112027Sjungma@eit.uni-kl.de sc_cor_pthread* p = (sc_cor_pthread*)context_p; 10212027Sjungma@eit.uni-kl.de DEBUGF << p << ": sc_cor_pthread::invoke_module_method()" << std::endl; 10312027Sjungma@eit.uni-kl.de 10412027Sjungma@eit.uni-kl.de 10512027Sjungma@eit.uni-kl.de // SUSPEND THE THREAD SO WE CAN GAIN CONTROL FROM THE PTHREAD PACKAGE: 10612027Sjungma@eit.uni-kl.de // 10712027Sjungma@eit.uni-kl.de // Since pthread_create schedules each thread behind our back for its 10812027Sjungma@eit.uni-kl.de // initial execution we immediately suspend a newly created thread 10912027Sjungma@eit.uni-kl.de // here so we can control when its execution will occur. We also wake 11012027Sjungma@eit.uni-kl.de // up the main thread which is waiting for this thread to execute to this 11112027Sjungma@eit.uni-kl.de // wait point. 11212027Sjungma@eit.uni-kl.de 11312027Sjungma@eit.uni-kl.de pthread_mutex_lock( &create_mutex ); 11412027Sjungma@eit.uni-kl.de DEBUGF << p << ": child signalling main thread " << endl; 11512027Sjungma@eit.uni-kl.de pthread_cond_signal( &create_condition ); 11612027Sjungma@eit.uni-kl.de pthread_mutex_lock( &p->m_mutex ); 11712027Sjungma@eit.uni-kl.de pthread_mutex_unlock( &create_mutex ); 11812027Sjungma@eit.uni-kl.de pthread_cond_wait( &p->m_pt_condition, &p->m_mutex ); 11912027Sjungma@eit.uni-kl.de pthread_mutex_unlock( &p->m_mutex ); 12012027Sjungma@eit.uni-kl.de 12112027Sjungma@eit.uni-kl.de 12212027Sjungma@eit.uni-kl.de // CALL THE SYSTEMC CODE THAT WILL ACTUALLY START THE THREAD OFF: 12312027Sjungma@eit.uni-kl.de 12412027Sjungma@eit.uni-kl.de active_cor_p = p; 12512027Sjungma@eit.uni-kl.de DEBUGF << p << ": about to invoke real method " 12612027Sjungma@eit.uni-kl.de << active_cor_p << std::endl; 12712027Sjungma@eit.uni-kl.de (p->m_cor_fn)(p->m_cor_fn_arg); 12812027Sjungma@eit.uni-kl.de 12912027Sjungma@eit.uni-kl.de return 0; 13012027Sjungma@eit.uni-kl.de} 13112027Sjungma@eit.uni-kl.de 13212027Sjungma@eit.uni-kl.de 13312027Sjungma@eit.uni-kl.de// ---------------------------------------------------------------------------- 13412027Sjungma@eit.uni-kl.de// CLASS : sc_cor_pkg_pthread 13512027Sjungma@eit.uni-kl.de// 13612027Sjungma@eit.uni-kl.de// Coroutine package class implemented with Posix Threads. 13712027Sjungma@eit.uni-kl.de// ---------------------------------------------------------------------------- 13812027Sjungma@eit.uni-kl.de 13912027Sjungma@eit.uni-kl.deint sc_cor_pkg_pthread::instance_count = 0; 14012027Sjungma@eit.uni-kl.de 14112027Sjungma@eit.uni-kl.de 14212027Sjungma@eit.uni-kl.de// constructor 14312027Sjungma@eit.uni-kl.de 14412027Sjungma@eit.uni-kl.desc_cor_pkg_pthread::sc_cor_pkg_pthread( sc_simcontext* simc ) 14512027Sjungma@eit.uni-kl.de: sc_cor_pkg( simc ) 14612027Sjungma@eit.uni-kl.de{ 14712027Sjungma@eit.uni-kl.de // initialize the current coroutine 14812027Sjungma@eit.uni-kl.de if( ++ instance_count == 1 ) 14912027Sjungma@eit.uni-kl.de { 15012027Sjungma@eit.uni-kl.de pthread_cond_init( &create_condition, PTHREAD_NULL ); 15112027Sjungma@eit.uni-kl.de pthread_mutex_init( &create_mutex, PTHREAD_NULL ); 15212027Sjungma@eit.uni-kl.de assert( active_cor_p == 0 ); 15312027Sjungma@eit.uni-kl.de main_cor.m_pkg_p = this; 15412027Sjungma@eit.uni-kl.de DEBUGF << &main_cor << ": is main co-routine" << std::endl; 15512027Sjungma@eit.uni-kl.de active_cor_p = &main_cor; 15612027Sjungma@eit.uni-kl.de } 15712027Sjungma@eit.uni-kl.de} 15812027Sjungma@eit.uni-kl.de 15912027Sjungma@eit.uni-kl.de 16012027Sjungma@eit.uni-kl.de// destructor 16112027Sjungma@eit.uni-kl.de 16212027Sjungma@eit.uni-kl.desc_cor_pkg_pthread::~sc_cor_pkg_pthread() 16312027Sjungma@eit.uni-kl.de{ 16412027Sjungma@eit.uni-kl.de if( -- instance_count == 0 ) { 16512027Sjungma@eit.uni-kl.de // cleanup the main coroutine 16612027Sjungma@eit.uni-kl.de } 16712027Sjungma@eit.uni-kl.de} 16812027Sjungma@eit.uni-kl.de 16912027Sjungma@eit.uni-kl.de 17012027Sjungma@eit.uni-kl.de// create a new coroutine 17112027Sjungma@eit.uni-kl.de 17212027Sjungma@eit.uni-kl.desc_cor* 17312027Sjungma@eit.uni-kl.desc_cor_pkg_pthread::create( std::size_t stack_size, sc_cor_fn* fn, void* arg ) 17412027Sjungma@eit.uni-kl.de{ 17512027Sjungma@eit.uni-kl.de sc_cor_pthread* cor_p = new sc_cor_pthread; 17612027Sjungma@eit.uni-kl.de DEBUGF << &main_cor << ": sc_cor_pkg_pthread::create(" 17712027Sjungma@eit.uni-kl.de << cor_p << ")" << std::endl; 17812027Sjungma@eit.uni-kl.de 17912027Sjungma@eit.uni-kl.de 18012027Sjungma@eit.uni-kl.de // INITIALIZE OBJECT'S FIELDS FROM ARGUMENT LIST: 18112027Sjungma@eit.uni-kl.de 18212027Sjungma@eit.uni-kl.de cor_p->m_pkg_p = this; 18312027Sjungma@eit.uni-kl.de cor_p->m_cor_fn = fn; 18412027Sjungma@eit.uni-kl.de cor_p->m_cor_fn_arg = arg; 18512027Sjungma@eit.uni-kl.de 18612027Sjungma@eit.uni-kl.de 18712027Sjungma@eit.uni-kl.de // SET UP THREAD CREATION ATTRIBUTES: 18812027Sjungma@eit.uni-kl.de // 18912027Sjungma@eit.uni-kl.de // Use default values except for stack size. If stack size is non-zero 19012027Sjungma@eit.uni-kl.de // set it. 19112027Sjungma@eit.uni-kl.de 19212027Sjungma@eit.uni-kl.de pthread_attr_t attr; 19312027Sjungma@eit.uni-kl.de pthread_attr_init( &attr ); 19412027Sjungma@eit.uni-kl.de if ( stack_size != 0 ) 19512027Sjungma@eit.uni-kl.de { 19612027Sjungma@eit.uni-kl.de pthread_attr_setstacksize( &attr, stack_size ); 19712027Sjungma@eit.uni-kl.de } 19812027Sjungma@eit.uni-kl.de 19912027Sjungma@eit.uni-kl.de 20012027Sjungma@eit.uni-kl.de // ALLOCATE THE POSIX THREAD TO USE AND FORCE SEQUENTIAL EXECUTION: 20112027Sjungma@eit.uni-kl.de // 20212027Sjungma@eit.uni-kl.de // Because pthread_create causes the created thread to be executed, 20312027Sjungma@eit.uni-kl.de // we need to let it run until we can block in the invoke_module_method. 20412027Sjungma@eit.uni-kl.de // So we: 20512027Sjungma@eit.uni-kl.de // (1) Lock the creation mutex before creating the new thread. 20612027Sjungma@eit.uni-kl.de // (2) Sleep on the creation condition, which will be signalled by 20712027Sjungma@eit.uni-kl.de // the newly created thread just before it goes to sleep in 20812027Sjungma@eit.uni-kl.de // invoke_module_method. 20912027Sjungma@eit.uni-kl.de // This scheme results in the newly created thread being dormant before 21012027Sjungma@eit.uni-kl.de // the main thread continues execution. 21112027Sjungma@eit.uni-kl.de 21212027Sjungma@eit.uni-kl.de pthread_mutex_lock( &create_mutex ); 21312027Sjungma@eit.uni-kl.de DEBUGF << &main_cor << ": about to create actual thread " 21412027Sjungma@eit.uni-kl.de << cor_p << std::endl; 21512027Sjungma@eit.uni-kl.de if ( pthread_create( &cor_p->m_thread, &attr, 21612027Sjungma@eit.uni-kl.de &sc_cor_pthread::invoke_module_method, (void*)cor_p ) ) 21712027Sjungma@eit.uni-kl.de { 21812027Sjungma@eit.uni-kl.de std::fprintf(stderr, "ERROR - could not create thread\n"); 21912027Sjungma@eit.uni-kl.de } 22012027Sjungma@eit.uni-kl.de 22112027Sjungma@eit.uni-kl.de DEBUGF << &main_cor << ": main thread waiting for signal from " 22212027Sjungma@eit.uni-kl.de << cor_p << std::endl; 22312027Sjungma@eit.uni-kl.de pthread_cond_wait( &create_condition, &create_mutex ); 22412027Sjungma@eit.uni-kl.de DEBUGF << &main_cor << ": main thread signaled by " 22512027Sjungma@eit.uni-kl.de << cor_p << endl; 22612027Sjungma@eit.uni-kl.de pthread_attr_destroy( &attr ); 22712027Sjungma@eit.uni-kl.de pthread_mutex_unlock( &create_mutex ); 22812027Sjungma@eit.uni-kl.de DEBUGF << &main_cor << ": exiting sc_cor_pkg_pthread::create(" 22912027Sjungma@eit.uni-kl.de << cor_p << ")" << std::endl; 23012027Sjungma@eit.uni-kl.de 23112027Sjungma@eit.uni-kl.de return cor_p; 23212027Sjungma@eit.uni-kl.de} 23312027Sjungma@eit.uni-kl.de 23412027Sjungma@eit.uni-kl.de 23512027Sjungma@eit.uni-kl.de// yield to the next coroutine 23612027Sjungma@eit.uni-kl.de// 23712027Sjungma@eit.uni-kl.de// We don't do anything after the p_thread_cond_wait since it won't 23812027Sjungma@eit.uni-kl.de// happen until the thread wakes up again! 23912027Sjungma@eit.uni-kl.de 24012027Sjungma@eit.uni-kl.devoid 24112027Sjungma@eit.uni-kl.desc_cor_pkg_pthread::yield( sc_cor* next_cor_p ) 24212027Sjungma@eit.uni-kl.de{ 24312027Sjungma@eit.uni-kl.de sc_cor_pthread* from_p = active_cor_p; 24412027Sjungma@eit.uni-kl.de sc_cor_pthread* to_p = (sc_cor_pthread*)next_cor_p; 24512027Sjungma@eit.uni-kl.de 24612027Sjungma@eit.uni-kl.de DEBUGF << from_p << ": switch to " << to_p << std::endl; 24712027Sjungma@eit.uni-kl.de if ( to_p != from_p ) 24812027Sjungma@eit.uni-kl.de { 24912027Sjungma@eit.uni-kl.de pthread_mutex_lock( &to_p->m_mutex ); 25012027Sjungma@eit.uni-kl.de pthread_cond_signal( &to_p->m_pt_condition ); 25112027Sjungma@eit.uni-kl.de pthread_mutex_lock( &from_p->m_mutex ); 25212027Sjungma@eit.uni-kl.de pthread_mutex_unlock( &to_p->m_mutex ); 25312027Sjungma@eit.uni-kl.de pthread_cond_wait( &from_p->m_pt_condition, &from_p->m_mutex ); 25412027Sjungma@eit.uni-kl.de pthread_mutex_unlock( &from_p->m_mutex ); 25512027Sjungma@eit.uni-kl.de } 25612027Sjungma@eit.uni-kl.de 25712027Sjungma@eit.uni-kl.de active_cor_p = from_p; // When we come out of wait make ourselves active. 25812027Sjungma@eit.uni-kl.de DEBUGF << from_p << " restarting after yield to " << to_p << std::endl; 25912027Sjungma@eit.uni-kl.de} 26012027Sjungma@eit.uni-kl.de 26112027Sjungma@eit.uni-kl.de 26212027Sjungma@eit.uni-kl.de// abort the current coroutine (and resume the next coroutine) 26312027Sjungma@eit.uni-kl.de 26412027Sjungma@eit.uni-kl.devoid 26512027Sjungma@eit.uni-kl.desc_cor_pkg_pthread::abort( sc_cor* next_cor_p ) 26612027Sjungma@eit.uni-kl.de{ 26712027Sjungma@eit.uni-kl.de sc_cor_pthread* n_p = (sc_cor_pthread*)next_cor_p; 26812027Sjungma@eit.uni-kl.de 26912027Sjungma@eit.uni-kl.de DEBUGF << active_cor_p << ": aborting, switching to " << n_p << std::endl; 27012027Sjungma@eit.uni-kl.de pthread_mutex_lock( &n_p->m_mutex ); 27112027Sjungma@eit.uni-kl.de pthread_cond_signal( &n_p->m_pt_condition ); 27212027Sjungma@eit.uni-kl.de pthread_mutex_unlock( &n_p->m_mutex ); 27312027Sjungma@eit.uni-kl.de} 27412027Sjungma@eit.uni-kl.de 27512027Sjungma@eit.uni-kl.de 27612027Sjungma@eit.uni-kl.de// get the main coroutine 27712027Sjungma@eit.uni-kl.de 27812027Sjungma@eit.uni-kl.desc_cor* 27912027Sjungma@eit.uni-kl.desc_cor_pkg_pthread::get_main() 28012027Sjungma@eit.uni-kl.de{ 28112027Sjungma@eit.uni-kl.de return &main_cor; 28212027Sjungma@eit.uni-kl.de} 28312027Sjungma@eit.uni-kl.de 28412027Sjungma@eit.uni-kl.de} // namespace sc_core 28512027Sjungma@eit.uni-kl.de 28612027Sjungma@eit.uni-kl.de#endif // !defined(_WIN32) && !defined(WIN32) && defined(SC_USE_PTHREADS) 28712027Sjungma@eit.uni-kl.de 28812027Sjungma@eit.uni-kl.de 28912027Sjungma@eit.uni-kl.de// $Log: sc_cor_pthread.cpp,v $ 29012027Sjungma@eit.uni-kl.de// Revision 1.6 2011/08/30 21:51:04 acg 29112027Sjungma@eit.uni-kl.de// Jerome Cornet: auto processing of pthread configurations. 29212027Sjungma@eit.uni-kl.de// 29312027Sjungma@eit.uni-kl.de// Revision 1.5 2011/08/26 20:46:09 acg 29412027Sjungma@eit.uni-kl.de// Andy Goodrich: moved the modification log to the end of the file to 29512027Sjungma@eit.uni-kl.de// eliminate source line number skew when check-ins are done. 29612027Sjungma@eit.uni-kl.de// 29712027Sjungma@eit.uni-kl.de// Revision 1.4 2011/02/18 20:27:14 acg 29812027Sjungma@eit.uni-kl.de// Andy Goodrich: Updated Copyrights. 29912027Sjungma@eit.uni-kl.de// 30012027Sjungma@eit.uni-kl.de// Revision 1.3 2011/02/13 21:47:37 acg 30112027Sjungma@eit.uni-kl.de// Andy Goodrich: update copyright notice. 30212027Sjungma@eit.uni-kl.de// 30312027Sjungma@eit.uni-kl.de// Revision 1.2 2008/05/22 17:06:25 acg 30412027Sjungma@eit.uni-kl.de// Andy Goodrich: updated copyright notice to include 2008. 30512027Sjungma@eit.uni-kl.de// 30612027Sjungma@eit.uni-kl.de// Revision 1.1.1.1 2006/12/15 20:20:05 acg 30712027Sjungma@eit.uni-kl.de// SystemC 2.3 30812027Sjungma@eit.uni-kl.de// 30912027Sjungma@eit.uni-kl.de// Revision 1.3 2006/01/13 18:44:29 acg 31012027Sjungma@eit.uni-kl.de// Added $Log to record CVS changes into the source. 31112027Sjungma@eit.uni-kl.de// 31212027Sjungma@eit.uni-kl.de 31312027Sjungma@eit.uni-kl.de// Taf! 314