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_qt.cpp -- Coroutine implementation with QuickThreads. 23 24 Original Author: Martin Janssen, Synopsys, Inc., 2001-12-18 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#include <unistd.h> 32#include <sys/mman.h> 33#include <sys/types.h> 34 35#include "sysc/kernel/sc_cor_qt.h" 36#include "sysc/kernel/sc_simcontext.h" 37 38namespace sc_core { 39 40// ---------------------------------------------------------------------------- 41// File static variables. 42// ---------------------------------------------------------------------------- 43 44// main coroutine 45 46static sc_cor_qt main_cor; 47 48// current coroutine 49 50static sc_cor_qt* curr_cor = 0; 51 52 53// ---------------------------------------------------------------------------- 54// CLASS : sc_cor_qt 55// 56// Coroutine class implemented with QuickThreads. 57// ---------------------------------------------------------------------------- 58 59// switch stack protection on/off 60 61void 62sc_cor_qt::stack_protect( bool enable ) 63{ 64 // Code needs to be tested on HP-UX and disabled if it doesn't work there 65 // Code still needs to be ported to WIN32 66 67 static std::size_t pagesize; 68 69 if( pagesize == 0 ) { 70# if defined(__ppc__) 71 pagesize = getpagesize(); 72# else 73 pagesize = sysconf( _SC_PAGESIZE ); 74# endif 75 } 76 77 assert( pagesize != 0 ); 78 assert( m_stack_size > ( 2 * pagesize ) ); 79 80#ifdef QUICKTHREADS_GROW_DOWN 81 // Stacks grow from high address down to low address 82 caddr_t redzone = caddr_t( ( ( std::size_t( m_stack ) + pagesize - 1 ) / 83 pagesize ) * pagesize ); 84#else 85 // Stacks grow from low address up to high address 86 caddr_t redzone = caddr_t( ( ( std::size_t( m_stack ) + 87 m_stack_size - pagesize ) / 88 pagesize ) * pagesize ); 89#endif 90 91 int ret; 92 93 // Enable the red zone at the end of the stack so that references within 94 // it will cause an interrupt. 95 96 if( enable ) { 97 ret = mprotect( redzone, pagesize - 1, PROT_NONE ); 98 } 99 100 // Revert the red zone to normal memory usage. Try to make it read - write - 101 // execute. If that does not work then settle for read - write 102 103 else { 104 ret = mprotect( redzone, pagesize - 1, PROT_READ|PROT_WRITE|PROT_EXEC); 105 if ( ret != 0 ) 106 ret = mprotect( redzone, pagesize - 1, PROT_READ | PROT_WRITE ); 107 } 108 109 assert( ret == 0 ); 110} 111 112 113// ---------------------------------------------------------------------------- 114// CLASS : sc_cor_pkg_qt 115// 116// Coroutine package class implemented with QuickThreads. 117// ---------------------------------------------------------------------------- 118 119int sc_cor_pkg_qt::instance_count = 0; 120 121 122// support function 123 124inline 125void* 126stack_align( void* sp, int alignment, std::size_t* stack_size ) 127{ 128 int round_up_mask = alignment - 1; 129 *stack_size = (*stack_size + round_up_mask) & ~round_up_mask; 130 return ( (void*)(((qt_word_t) sp + round_up_mask) & ~round_up_mask) ); 131} 132 133 134// constructor 135 136sc_cor_pkg_qt::sc_cor_pkg_qt( sc_simcontext* simc ) 137: sc_cor_pkg( simc ) 138{ 139 if( ++ instance_count == 1 ) { 140 // initialize the current coroutine 141 assert( curr_cor == 0 ); 142 curr_cor = &main_cor; 143 } 144} 145 146 147// destructor 148 149sc_cor_pkg_qt::~sc_cor_pkg_qt() 150{ 151 if( -- instance_count == 0 ) { 152 // cleanup the current coroutine 153 curr_cor = 0; 154 } 155} 156 157 158// create a new coroutine 159 160extern "C" 161void 162sc_cor_qt_wrapper( void* arg, void* cor, qt_userf_t* fn ) 163{ 164 curr_cor = RCAST<sc_cor_qt*>( cor ); 165 // invoke the user function 166 (*(sc_cor_fn*) fn)( arg ); 167 // not reached 168} 169 170sc_cor* 171sc_cor_pkg_qt::create( std::size_t stack_size, sc_cor_fn* fn, void* arg ) 172{ 173 sc_cor_qt* cor = new sc_cor_qt(); 174 cor->m_pkg = this; 175 cor->m_stack_size = stack_size; 176 cor->m_stack = new char[cor->m_stack_size]; 177 void* sto = stack_align( cor->m_stack, QUICKTHREADS_STKALIGN, 178 &cor->m_stack_size ); 179 cor->m_sp = QUICKTHREADS_SP(sto, cor->m_stack_size - QUICKTHREADS_STKALIGN); 180 cor->m_sp = QUICKTHREADS_ARGS( cor->m_sp, arg, cor, (qt_userf_t*) fn, 181 sc_cor_qt_wrapper ); 182 return cor; 183} 184 185 186// yield to the next coroutine 187 188extern "C" 189void* 190sc_cor_qt_yieldhelp( qt_t* sp, void* old_cor, void* ) 191{ 192 RCAST<sc_cor_qt*>( old_cor )->m_sp = sp; 193 return 0; 194} 195 196void 197sc_cor_pkg_qt::yield( sc_cor* next_cor ) 198{ 199 sc_cor_qt* new_cor = SCAST<sc_cor_qt*>( next_cor ); 200 sc_cor_qt* old_cor = curr_cor; 201 curr_cor = new_cor; 202 QUICKTHREADS_BLOCK( sc_cor_qt_yieldhelp, old_cor, 0, new_cor->m_sp ); 203} 204 205 206// abort the current coroutine (and resume the next coroutine) 207 208extern "C" 209void* 210sc_cor_qt_aborthelp( qt_t*, void*, void* ) 211{ 212 return 0; 213} 214 215void 216sc_cor_pkg_qt::abort( sc_cor* next_cor ) 217{ 218 sc_cor_qt* new_cor = SCAST<sc_cor_qt*>( next_cor ); 219 sc_cor_qt* old_cor = curr_cor; 220 curr_cor = new_cor; 221 QUICKTHREADS_ABORT( sc_cor_qt_aborthelp, old_cor, 0, new_cor->m_sp ); 222} 223 224 225// get the main coroutine 226 227sc_cor* 228sc_cor_pkg_qt::get_main() 229{ 230 return &main_cor; 231} 232 233} // namespace sc_core 234 235#endif 236 237// $Log: sc_cor_qt.cpp,v $ 238// Revision 1.9 2011/08/29 18:04:32 acg 239// Philipp A. Hartmann: miscellaneous clean ups. 240// 241// Revision 1.8 2011/08/26 20:46:09 acg 242// Andy Goodrich: moved the modification log to the end of the file to 243// eliminate source line number skew when check-ins are done. 244// 245// Revision 1.7 2011/02/18 20:27:14 acg 246// Andy Goodrich: Updated Copyrights. 247// 248// Revision 1.6 2011/02/13 21:47:37 acg 249// Andy Goodrich: update copyright notice. 250// 251// Revision 1.5 2010/08/03 16:52:14 acg 252// Andy Goodrich: line formatting. 253// 254// Revision 1.4 2008/11/11 14:03:07 acg 255// Andy Goodrich: added execute access to the release of red zone storage 256// per Ulli's suggestion. 257// 258// Revision 1.3 2008/05/22 17:06:25 acg 259// Andy Goodrich: updated copyright notice to include 2008. 260// 261// Revision 1.2 2008/03/24 18:32:36 acg 262// Andy Goodrich: added include of sys/types.h to pick up the declaration 263// of caddr_t. 264// 265// Revision 1.1.1.1 2006/12/15 20:20:05 acg 266// SystemC 2.3 267// 268// Revision 1.3 2006/01/13 18:44:29 acg 269// Added $Log to record CVS changes into the source. 270 271// Taf! 272