2007-11-15 03:18:48 +00:00
/*
* " $Id: rsthreads.cc,v 1.1 2007-02-19 20:08:30 rmf24 Exp $ "
*
* RetroShare C + + Interface .
*
* Copyright 2004 - 2007 by Robert Fernie .
*
* This library is free software ; you can redistribute it and / or
* modify it under the terms of the GNU Library General Public
* License Version 2 as published by the Free Software Foundation .
*
* This library is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the GNU
* Library General Public License for more details .
*
* You should have received a copy of the GNU Library General Public
* License along with this library ; if not , write to the Free Software
* Foundation , Inc . , 59 Temple Place , Suite 330 , Boston , MA 02111 - 1307
* USA .
*
* Please report all bugs and problems to " retroshare@lunamutt.com " .
*
*/
# include "rsthreads.h"
2014-10-24 21:31:58 +00:00
# include <unistd.h> // for usleep()
# include <errno.h> // for errno
2011-03-30 22:32:13 +00:00
# include <iostream>
2013-10-21 11:00:49 +00:00
# include <time.h>
2013-08-31 08:16:09 +00:00
2011-07-04 22:59:39 +00:00
# ifdef RSMUTEX_DEBUG
# include <stdio.h>
2014-10-28 20:37:48 +00:00
# include <sys/time.h>
2011-07-04 22:59:39 +00:00
# endif
2008-11-02 11:38:11 +00:00
/*******
* # define DEBUG_THREADS 1
2013-08-31 08:16:09 +00:00
* # define RSMUTEX_ABORT 1 // Catch wrong pthreads mode.
2008-11-02 11:38:11 +00:00
* * * * * * */
2013-08-31 08:16:09 +00:00
# ifdef RSMUTEX_ABORT
# include <stdlib.h>
# endif
2008-11-02 11:38:11 +00:00
# ifdef DEBUG_THREADS
# include <iostream>
# endif
2007-11-15 03:18:48 +00:00
extern " C " void * rsthread_init ( void * p )
{
RsThread * thread = ( RsThread * ) p ;
if ( ! thread )
{
return 0 ;
}
thread - > run ( ) ;
return 0 ;
}
pthread_t createThread ( RsThread & thread )
{
pthread_t tid ;
void * data = ( void * ) ( & thread ) ;
thread . mMutex . lock ( ) ;
{
2009-08-04 23:22:44 +00:00
#if 0
int ret ;
ret = pthread_attr_init ( & tattr ) ;
if ( doDetached )
{
ret = pthread_attr_setdetachstate ( & tattr , PTHREAD_CREATE_DETACHED ) ;
}
else
{
ret = pthread_attr_setdetachstate ( & tattr , PTHREAD_CREATE_JOINABLE ) ;
}
pthread_create ( & tid , & tattr , & rsthread_init , data ) ;
# endif
2011-03-30 22:32:13 +00:00
int err ;
if ( 0 = = ( err = pthread_create ( & tid , 0 , & rsthread_init , data ) ) )
thread . mTid = tid ;
else
std : : cerr < < " Fatal error: pthread_create could not create a thread. Error returned: " < < err < < " !!!!!!! " < < std : : endl ;
2007-11-15 03:18:48 +00:00
}
thread . mMutex . unlock ( ) ;
return tid ;
}
2011-07-04 22:59:39 +00:00
RsThread : : RsThread ( ) : mMutex ( " RsThread " )
2010-05-29 15:14:25 +00:00
{
2011-03-03 23:30:08 +00:00
mIsRunning = true ;
2010-08-03 14:26:54 +00:00
# ifdef WINDOWS_SYS
memset ( & mTid , 0 , sizeof ( mTid ) ) ;
# else
mTid = 0 ;
# endif
2010-05-29 15:14:25 +00:00
}
2009-08-04 23:22:44 +00:00
void RsThread : : join ( ) /* waits for the the mTid thread to stop */
{
2011-03-03 23:30:08 +00:00
// do we need a mutex for this ?
mIsRunning = false ;
2010-05-29 15:14:25 +00:00
2009-08-04 23:22:44 +00:00
void * ptr ;
pthread_join ( mTid , & ptr ) ;
}
void RsThread : : stop ( )
{
pthread_exit ( NULL ) ;
}
2007-11-15 03:18:48 +00:00
2011-03-03 23:30:08 +00:00
bool RsThread : : isRunning ( )
{
// do we need a mutex for this ?
return mIsRunning ;
}
2008-07-23 22:01:59 +00:00
RsQueueThread : : RsQueueThread ( uint32_t min , uint32_t max , double relaxFactor )
: mMinSleep ( min ) , mMaxSleep ( max ) , mRelaxFactor ( relaxFactor )
{
2009-03-09 12:09:11 +00:00
mLastSleep = ( uint32_t ) mMinSleep ;
2010-03-28 20:46:45 +00:00
mLastWork = time ( NULL ) ;
2008-07-23 22:01:59 +00:00
}
void RsQueueThread : : run ( )
{
2011-03-03 23:30:08 +00:00
while ( isRunning ( ) )
2008-07-23 22:01:59 +00:00
{
bool doneWork = false ;
while ( workQueued ( ) & & doWork ( ) )
{
doneWork = true ;
}
time_t now = time ( NULL ) ;
if ( doneWork )
{
mLastWork = now ;
2009-03-09 12:09:11 +00:00
mLastSleep = ( uint32_t ) ( mMinSleep + ( mLastSleep - mMinSleep ) / 2.0 ) ;
2008-11-02 11:38:11 +00:00
# ifdef DEBUG_THREADS
std : : cerr < < " RsQueueThread::run() done work: sleeping for: " < < mLastSleep ;
std : : cerr < < " ms " ;
std : : cerr < < std : : endl ;
# endif
2008-07-23 22:01:59 +00:00
}
else
{
uint32_t deltaT = now - mLastWork ;
double frac = deltaT / mRelaxFactor ;
mLastSleep + = ( uint32_t )
( ( mMaxSleep - mMinSleep ) * ( frac + 0.05 ) ) ;
if ( mLastSleep > mMaxSleep )
{
mLastSleep = mMaxSleep ;
}
2008-11-02 11:38:11 +00:00
# ifdef DEBUG_THREADS
std : : cerr < < " RsQueueThread::run() no work: sleeping for: " < < mLastSleep ;
std : : cerr < < " ms " ;
std : : cerr < < std : : endl ;
# endif
2008-07-23 22:01:59 +00:00
}
2014-10-24 21:31:58 +00:00
usleep ( mLastSleep * 1000 ) ; // mLastSleep msec
2008-07-23 22:01:59 +00:00
}
}
2011-07-04 22:59:39 +00:00
2014-10-28 20:37:48 +00:00
void RsMutex : : unlock ( )
{
# ifdef RSTHREAD_SELF_LOCKING_GUARD
if ( - - _cnt = = 0 )
{
# endif
# ifndef WIN32
_thread_id = 0 ;
# endif
# ifdef RSMUTEX_DEBUG
double ts = getCurrentTS ( ) ;
if ( ts - _time_stamp > 1.0 ) // locked for more than 0.5 seconds => somthing fishy is happenning
2014-11-05 20:07:15 +00:00
std : : cerr < < " Mutex " < < ( void * ) this < < " \" " < < name < < " \" " < < " got locked for " < < ts - _time_stamp < < " seconds in thread " < < pthread_self ( ) < < std : : endl ;
2014-10-28 20:37:48 +00:00
# endif
pthread_mutex_unlock ( & realMutex ) ;
# ifdef RSTHREAD_SELF_LOCKING_GUARD
}
# endif
}
2011-07-04 22:59:39 +00:00
void RsMutex : : lock ( )
{
# ifdef RSMUTEX_DEBUG
2014-10-28 20:37:48 +00:00
_time_stamp = getCurrentTS ( ) ;
2014-11-05 20:07:15 +00:00
pthread_t owner = _thread_id ;
2011-07-04 22:59:39 +00:00
# endif
2013-08-31 08:16:09 +00:00
int retval = 0 ;
2011-07-04 22:59:39 +00:00
# ifdef RSTHREAD_SELF_LOCKING_GUARD
if ( ! trylock ( ) )
if ( ! pthread_equal ( _thread_id , pthread_self ( ) ) )
# endif
2013-08-31 08:16:09 +00:00
retval = pthread_mutex_lock ( & realMutex ) ;
2014-10-28 20:37:48 +00:00
# ifdef RSMUTEX_DEBUG
double ts = getCurrentTS ( ) ;
if ( ts - _time_stamp > 1.0 )
2014-11-05 20:07:15 +00:00
std : : cerr < < " Mutex " < < ( void * ) this < < " \" " < < name < < " \" " < < " waited for " < < ts - _time_stamp < < " seconds in thread " < < pthread_self ( ) < < " for locked thread " < < owner < < std : : endl ;
_time_stamp = getCurrentTS ( ) ; // This is to re-init the locking time without accounting for how much we waited.
2014-10-28 20:37:48 +00:00
# endif
2013-08-31 08:16:09 +00:00
switch ( retval )
{
case 0 :
break ;
case EINVAL :
std : : cerr < < " RsMutex::lock() pthread_mutex_lock returned EINVAL " ;
std : : cerr < < std : : endl ;
break ;
case EBUSY :
std : : cerr < < " RsMutex::lock() pthread_mutex_lock returned EBUSY " ;
std : : cerr < < std : : endl ;
break ;
case EAGAIN :
std : : cerr < < " RsMutex::lock() pthread_mutex_lock returned EAGAIN " ;
std : : cerr < < std : : endl ;
break ;
case EDEADLK :
std : : cerr < < " RsMutex::lock() pthread_mutex_lock returned EDEADLK " ;
std : : cerr < < std : : endl ;
break ;
case EPERM :
std : : cerr < < " RsMutex::lock() pthread_mutex_lock returned EPERM " ;
std : : cerr < < std : : endl ;
break ;
default :
std : : cerr < < " RsMutex::lock() pthread_mutex_lock returned UNKNOWN ERROR " ;
std : : cerr < < std : : endl ;
break ;
}
/* Here is some debugging code - to catch failed locking attempts.
* Major bug is it is ever triggered .
*/
# ifdef RSMUTEX_ABORT
if ( retval ! = 0 )
{
# ifdef RSMUTEX_DEBUG
std : : cerr < < " RsMutex::lock() name: " < < name < < std : : endl ;
# endif
std : : cerr < < " RsMutex::lock() pthread_mutex_lock returned an Error. Aborting() " ;
std : : cerr < < std : : endl ;
abort ( ) ;
}
# endif
2011-07-04 22:59:39 +00:00
2013-08-31 08:16:09 +00:00
2011-07-04 22:59:39 +00:00
_thread_id = pthread_self ( ) ;
# ifdef RSTHREAD_SELF_LOCKING_GUARD
+ + _cnt ;
# endif
2014-10-28 20:37:48 +00:00
}
2011-07-04 22:59:39 +00:00
# ifdef RSMUTEX_DEBUG
2014-10-28 20:37:48 +00:00
double RsMutex : : getCurrentTS ( )
{
# ifndef WINDOWS_SYS
struct timeval cts_tmp ;
gettimeofday ( & cts_tmp , NULL ) ;
double cts = ( cts_tmp . tv_sec ) + ( ( double ) cts_tmp . tv_usec ) / 1000000.0 ;
# else
struct _timeb timebuf ;
_ftime ( & timebuf ) ;
double cts = ( timebuf . time ) + ( ( double ) timebuf . millitm ) / 1000.0 ;
2011-07-04 22:59:39 +00:00
# endif
2014-10-28 20:37:48 +00:00
return cts ;
2011-07-04 22:59:39 +00:00
}
2014-10-28 20:37:48 +00:00
# endif