OpenWalnut  1.4.0
WThreadedRunner.cpp
00001 //---------------------------------------------------------------------------
00002 //
00003 // Project: OpenWalnut ( http://www.openwalnut.org )
00004 //
00005 // Copyright 2009 OpenWalnut Community, BSV@Uni-Leipzig and CNCF@MPI-CBS
00006 // For more information see http://www.openwalnut.org/copying
00007 //
00008 // This file is part of OpenWalnut.
00009 //
00010 // OpenWalnut is free software: you can redistribute it and/or modify
00011 // it under the terms of the GNU Lesser General Public License as published by
00012 // the Free Software Foundation, either version 3 of the License, or
00013 // (at your option) any later version.
00014 //
00015 // OpenWalnut is distributed in the hope that it will be useful,
00016 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00017 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00018 // GNU Lesser General Public License for more details.
00019 //
00020 // You should have received a copy of the GNU Lesser General Public License
00021 // along with OpenWalnut. If not, see <http://www.gnu.org/licenses/>.
00022 //
00023 //---------------------------------------------------------------------------
00024 
00025 #if ( defined( __linux__ ) && !defined( __ANDROID__ ) )
00026 #include <sys/prctl.h>
00027 #endif
00028 
00029 #include <iostream>
00030 #include <string>
00031 
00032 #include "exceptions/WSignalSubscriptionFailed.h"
00033 #include "WCondition.h"
00034 #include "WConditionOneShot.h"
00035 #include "WException.h"
00036 #include "WLogger.h"
00037 #include "WThreadedRunner.h"
00038 
00039 WThreadedRunner::WThreadedRunner():
00040     m_shutdownFlag( new WConditionOneShot(), false ),
00041     m_isCrashed( new WConditionOneShot(), false ),
00042     m_crashMessage( "" ),
00043     m_threadName( "" )
00044 {
00045     // initialize members
00046 }
00047 
00048 WThreadedRunner::~WThreadedRunner()
00049 {
00050     // cleanup
00051 }
00052 
00053 const WBoolFlag& WThreadedRunner::isCrashed() const
00054 {
00055     return m_isCrashed;
00056 }
00057 
00058 void WThreadedRunner::onThreadException( const WException& e )
00059 {
00060     handleDeadlyException( e );
00061 }
00062 
00063 void WThreadedRunner::handleDeadlyException( const WException& e, std::string sender )
00064 {
00065     wlog::error( sender ) << "WException. Notifying. Message: " << e.what();
00066 
00067     // ensure proper exception propagation
00068     signal_thread_error( e );
00069 
00070     // notify waiting threads
00071     m_isCrashed( true );
00072     m_crashMessage = e.what();
00073 }
00074 
00075 void WThreadedRunner::run()
00076 {
00077     run( boost::bind( &WThreadedRunner::threadMainSave, this ) );
00078 }
00079 
00080 void WThreadedRunner::run( THREADFUNCTION f )
00081 {
00082     m_thread = boost::thread( f );
00083 }
00084 
00085 void WThreadedRunner::wait( bool requestFinish )
00086 {
00087     if( requestFinish )
00088     {
00089         requestStop();
00090     }
00091     m_thread.join();
00092 }
00093 
00094 void WThreadedRunner::requestStop()
00095 {
00096     // first notify
00097     notifyStop();
00098 
00099     // then signal it
00100     m_shutdownFlag( true );
00101 }
00102 
00103 void WThreadedRunner::waitForStop()
00104 {
00105     m_shutdownFlag.wait();
00106 }
00107 
00108 void WThreadedRunner::threadMainSave()
00109 {
00110     WThreadedRunner::setThisThreadName( getThreadName() );
00111 
00112     try
00113     {
00114         threadMain();
00115     }
00116     catch( const WException& e )
00117     {
00118         onThreadException( e );
00119     }
00120     catch( const std::exception& e )
00121     {
00122         onThreadException( WException( e ) );
00123     }
00124 }
00125 
00126 void WThreadedRunner::threadMain()
00127 {
00128     WLogger::getLogger()->addLogMessage( "This should never be called. Implement a thread function here.", "WThreadedRunner", LL_WARNING );
00129 }
00130 
00131 void WThreadedRunner::notifyStop()
00132 {
00133 }
00134 
00135 void WThreadedRunner::yield() const
00136 {
00137     m_thread.yield();
00138 }
00139 
00140 void WThreadedRunner::sleep( const int32_t t ) const
00141 {
00142     boost::this_thread::sleep( boost::posix_time::seconds( t ) );
00143 }
00144 
00145 void WThreadedRunner::msleep( const int32_t t ) const
00146 {
00147     boost::this_thread::sleep( boost::posix_time::microseconds( t ) );
00148 }
00149 
00150 boost::signals2::connection WThreadedRunner::subscribeSignal( THREAD_SIGNAL signal, t_ThreadErrorSignalHandlerType notifier )
00151 {
00152     switch( signal)
00153     {
00154         case WTHREAD_ERROR:
00155             return signal_thread_error.connect( notifier );
00156         default:
00157             throw WSignalSubscriptionFailed( "Could not subscribe to unknown signal." );
00158             break;
00159     }
00160 }
00161 
00162 void WThreadedRunner::setThreadName( std::string name )
00163 {
00164     m_threadName = name;
00165 }
00166 
00167 std::string WThreadedRunner::getThreadName() const
00168 {
00169     return m_threadName;
00170 }
00171 
00172 const std::string& WThreadedRunner::getCrashMessage() const
00173 {
00174     return m_crashMessage;
00175 }
00176 
00177 void WThreadedRunner::setThisThreadName( std::string name )
00178 {
00179 #if ( defined( __linux__ ) && !defined( __ANDROID__ ) )
00180     // set the name of the thread. This name is shown by the "top", for example.
00181     prctl( PR_SET_NAME, ( "openwalnut (" + name + ")" ).c_str() );
00182 #endif
00183 }