2018-05-30 21:34:38 +02:00
|
|
|
/*******************************************************************************
|
|
|
|
* libretroshare/src/util: rsthreads.cc *
|
|
|
|
* *
|
|
|
|
* libretroshare: retroshare core library *
|
|
|
|
* *
|
2019-10-31 18:23:38 +01:00
|
|
|
* Copyright (C) 2004-2007 Robert Fernie <retroshare@lunamutt.com> *
|
2021-11-04 19:17:57 +01:00
|
|
|
* Copyright (C) 2016-2021 Gioacchino Mazzurco <gio@eigenlab.org> *
|
|
|
|
* Copyright (C) 2019-2021 Asociación Civil Altermundi <info@altermundi.net> *
|
2018-05-30 21:34:38 +02:00
|
|
|
* *
|
|
|
|
* This program is free software: you can redistribute it and/or modify *
|
|
|
|
* it under the terms of the GNU Lesser General Public License as *
|
|
|
|
* published by the Free Software Foundation, either version 3 of the *
|
|
|
|
* License, or (at your option) any later version. *
|
|
|
|
* *
|
|
|
|
* This program 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 Lesser General Public License for more details. *
|
|
|
|
* *
|
|
|
|
* You should have received a copy of the GNU Lesser General Public License *
|
|
|
|
* along with this program. If not, see <https://www.gnu.org/licenses/>. *
|
|
|
|
* *
|
|
|
|
*******************************************************************************/
|
2007-11-15 03:18:48 +00:00
|
|
|
|
2020-12-08 17:15:16 +01:00
|
|
|
#include "rsthreads.h"
|
|
|
|
|
|
|
|
#include "util/rsdebug.h"
|
|
|
|
|
|
|
|
#include <chrono>
|
2020-02-05 15:01:45 +01:00
|
|
|
#include <ctime>
|
2020-12-08 17:15:16 +01:00
|
|
|
#include <iostream>
|
2019-10-31 18:23:38 +01:00
|
|
|
#include <thread>
|
|
|
|
|
2020-12-08 17:15:16 +01:00
|
|
|
#ifdef RS_MUTEX_DEBUG
|
2019-10-31 18:23:38 +01:00
|
|
|
#include <cstdio>
|
|
|
|
#include <sys/time.h>
|
|
|
|
#endif
|
|
|
|
|
2016-07-16 23:10:00 +02:00
|
|
|
#ifdef __APPLE__
|
|
|
|
int __attribute__((weak)) pthread_setname_np(const char *__buf) ;
|
|
|
|
int RS_pthread_setname_np(pthread_t /*__target_thread*/, const char *__buf) {
|
|
|
|
return pthread_setname_np(__buf);
|
|
|
|
}
|
|
|
|
#else
|
2021-03-05 17:39:12 +01:00
|
|
|
#ifndef __WIN64__
|
2016-06-03 19:03:10 +02:00
|
|
|
int __attribute__((weak)) pthread_setname_np(pthread_t __target_thread, const char *__buf) ;
|
2021-03-05 17:39:12 +01:00
|
|
|
#endif //__WIN64__
|
2016-07-16 23:10:00 +02:00
|
|
|
int RS_pthread_setname_np(pthread_t __target_thread, const char *__buf) {
|
|
|
|
return pthread_setname_np(__target_thread, __buf);
|
|
|
|
}
|
2021-03-05 17:39:12 +01:00
|
|
|
#endif //__APPLE__
|
2016-06-03 19:03:10 +02:00
|
|
|
|
2011-07-04 22:59:39 +00:00
|
|
|
|
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
|
|
|
*******/
|
2019-10-31 18:23:38 +01:00
|
|
|
#define THREAD_DEBUG RsDbg() << "[this=" << static_cast<void*>(this) \
|
|
|
|
<< ", caller thread ID: " << std::hex << pthread_self() << ", thread ID: " \
|
|
|
|
<< mTid << std::dec << "] "
|
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
|
|
|
|
|
2019-10-31 18:23:38 +01:00
|
|
|
/*static*/ void* RsThread::rsthread_init(void* p)
|
2017-05-30 20:57:20 +02:00
|
|
|
{
|
2019-10-31 18:23:38 +01:00
|
|
|
RsThread* thread = reinterpret_cast<RsThread *>(p);
|
|
|
|
if(!thread) return nullptr;
|
2017-05-30 20:57:20 +02:00
|
|
|
|
2019-10-31 18:23:38 +01:00
|
|
|
/* Using pthread_detach(...) the thread resources will be automatically
|
|
|
|
* freed when this function return, so there is no need for pthread_join()
|
|
|
|
* later. */
|
|
|
|
pthread_detach(pthread_self());
|
2015-05-22 20:54:38 +00:00
|
|
|
|
2016-05-04 22:34:03 -04:00
|
|
|
#ifdef DEBUG_THREADS
|
2019-10-31 18:23:38 +01:00
|
|
|
std::cerr << "[Thread ID:" << std::hex << pthread_self() << std::dec
|
|
|
|
<< "] thread is started. Calling wrapRun()..." << std::endl;
|
2016-05-04 22:34:03 -04:00
|
|
|
#endif
|
2019-10-31 18:23:38 +01:00
|
|
|
|
|
|
|
thread->wrapRun();
|
|
|
|
return nullptr;
|
2007-11-15 03:18:48 +00:00
|
|
|
}
|
2019-10-31 18:23:38 +01:00
|
|
|
|
2020-01-08 14:24:46 +01:00
|
|
|
void RsThread::resetTid()
|
2015-05-22 20:54:38 +00:00
|
|
|
{
|
|
|
|
#ifdef WINDOWS_SYS
|
2019-10-31 18:23:38 +01:00
|
|
|
memset (&mTid, 0, sizeof(mTid));
|
2015-05-22 20:54:38 +00:00
|
|
|
#else
|
2021-11-03 15:28:19 +01:00
|
|
|
mTid = pthread_t(); //Thread identifiers should be considered opaque and can be null.
|
2015-05-22 20:54:38 +00:00
|
|
|
#endif
|
|
|
|
}
|
2016-06-01 14:58:12 +02:00
|
|
|
|
2021-11-04 19:17:57 +01:00
|
|
|
RsThread::RsThread() : mInitMtx("RsThread"), mHasStopped(true),
|
|
|
|
mShouldStop(false), mLastTid()
|
2020-02-05 15:01:45 +01:00
|
|
|
#ifdef RS_THREAD_FORCE_STOP
|
|
|
|
, mStopTimeout(0)
|
|
|
|
#endif
|
2020-01-08 14:24:46 +01:00
|
|
|
{ resetTid(); }
|
|
|
|
|
2019-10-31 18:23:38 +01:00
|
|
|
bool RsThread::isRunning() { return !mHasStopped; }
|
2019-05-22 21:46:11 +02:00
|
|
|
|
2019-10-31 18:23:38 +01:00
|
|
|
bool RsThread::shouldStop() { return mShouldStop; }
|
2019-05-12 10:46:08 +02:00
|
|
|
|
2019-10-31 18:23:38 +01:00
|
|
|
void RsThread::askForStop()
|
2015-05-22 20:54:38 +00:00
|
|
|
{
|
2019-10-31 18:23:38 +01:00
|
|
|
/* Call onStopRequested() only once even if askForStop() is called multiple
|
|
|
|
* times */
|
2020-01-08 14:24:46 +01:00
|
|
|
if(!mShouldStop.exchange(true)) onStopRequested();
|
2015-05-22 20:54:38 +00:00
|
|
|
}
|
|
|
|
|
2019-10-31 18:23:38 +01:00
|
|
|
void RsThread::wrapRun()
|
2015-05-25 15:11:42 +00:00
|
|
|
{
|
2021-11-03 15:28:19 +01:00
|
|
|
{RS_STACK_MUTEX(mInitMtx);} // Waiting Init done.
|
2019-10-31 18:23:38 +01:00
|
|
|
run();
|
2020-01-08 14:24:46 +01:00
|
|
|
resetTid();
|
2019-10-31 18:23:38 +01:00
|
|
|
mHasStopped = true;
|
2015-05-25 15:11:42 +00:00
|
|
|
}
|
|
|
|
|
2019-10-31 18:23:38 +01:00
|
|
|
void RsThread::fullstop()
|
2021-11-04 19:17:57 +01:00
|
|
|
{
|
|
|
|
askForStop();
|
|
|
|
waitWhileStopping();
|
|
|
|
}
|
|
|
|
|
|
|
|
void RsThread::waitWhileStopping()
|
2015-05-22 18:16:49 +00:00
|
|
|
{
|
2020-02-05 15:01:45 +01:00
|
|
|
#ifdef RS_THREAD_FORCE_STOP
|
|
|
|
const rstime_t stopRequTS = time(nullptr);
|
|
|
|
#endif
|
|
|
|
|
2019-10-31 18:23:38 +01:00
|
|
|
const pthread_t callerTid = pthread_self();
|
|
|
|
if(pthread_equal(mTid, callerTid))
|
2018-02-24 14:07:25 +01:00
|
|
|
{
|
2019-10-31 18:23:38 +01:00
|
|
|
RsErr() << __PRETTY_FUNCTION__ << " called by same thread. This should "
|
|
|
|
<< "never happen! this: " << static_cast<void*>(this)
|
|
|
|
<< std::hex << ", callerTid: " << callerTid
|
2020-01-08 14:24:46 +01:00
|
|
|
<< ", mTid: " << mTid << std::dec
|
|
|
|
<< ", mFullName: " << mFullName << std::endl;
|
2018-02-24 14:07:25 +01:00
|
|
|
print_stacktrace();
|
|
|
|
return;
|
|
|
|
}
|
2010-05-29 15:14:25 +00:00
|
|
|
|
2020-01-06 14:46:36 +01:00
|
|
|
// Wait for the thread being stopped
|
|
|
|
auto i = 1;
|
|
|
|
while(!mHasStopped)
|
|
|
|
{
|
|
|
|
std::this_thread::sleep_for(std::chrono::milliseconds(200));
|
|
|
|
++i;
|
|
|
|
if(!(i%5))
|
2020-01-08 14:24:46 +01:00
|
|
|
RsDbg() << __PRETTY_FUNCTION__ << " " << i*0.2 << " seconds passed"
|
|
|
|
<< " waiting for thread: " << std::hex << mLastTid
|
|
|
|
<< std::dec << " " << mFullName << " to stop" << std::endl;
|
2020-02-05 15:01:45 +01:00
|
|
|
|
|
|
|
#ifdef RS_THREAD_FORCE_STOP
|
|
|
|
if(mStopTimeout && time(nullptr) > stopRequTS + mStopTimeout)
|
|
|
|
{
|
|
|
|
RsErr() << __PRETTY_FUNCTION__ << " thread mLastTid: " << std::hex
|
|
|
|
<< mLastTid << " mTid: " << mTid << std::dec << " "
|
|
|
|
<< mFullName
|
|
|
|
<< " ignored our nice stop request for more then "
|
|
|
|
<< mStopTimeout
|
|
|
|
<< " seconds, will be forcefully stopped. "
|
|
|
|
<< "Please submit a report to RetroShare developers"
|
|
|
|
<< std::endl;
|
|
|
|
|
|
|
|
const auto terr = pthread_cancel(mTid);
|
|
|
|
if(terr == 0) mHasStopped = true;
|
|
|
|
else
|
|
|
|
{
|
|
|
|
RsErr() << __PRETTY_FUNCTION__ << " pthread_cancel("
|
|
|
|
<< std::hex << mTid << std::dec <<") returned "
|
2021-11-04 19:17:57 +01:00
|
|
|
<< terr << " " << rs_errno_to_condition(terr)
|
|
|
|
<< std::endl;
|
2020-02-05 15:01:45 +01:00
|
|
|
print_stacktrace();
|
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
#endif // def RS_THREAD_FORCE_STOP
|
2020-01-06 14:46:36 +01:00
|
|
|
}
|
2015-05-25 15:11:42 +00:00
|
|
|
}
|
|
|
|
|
2019-10-31 18:23:38 +01:00
|
|
|
bool RsThread::start(const std::string& threadName)
|
2009-08-04 23:22:44 +00:00
|
|
|
{
|
2019-10-31 18:23:38 +01:00
|
|
|
// Atomically check if the thread was already started and set it as running
|
|
|
|
if(mHasStopped.exchange(false))
|
|
|
|
{
|
2021-11-03 15:28:19 +01:00
|
|
|
RS_STACK_MUTEX(mInitMtx); // Block thread starting to run
|
|
|
|
|
2019-10-31 18:23:38 +01:00
|
|
|
mShouldStop = false;
|
|
|
|
int pError = pthread_create(
|
|
|
|
&mTid, nullptr, &rsthread_init, static_cast<void*>(this) );
|
|
|
|
if(pError)
|
|
|
|
{
|
2021-11-04 19:17:57 +01:00
|
|
|
RS_ERR( "pthread_create could not create new thread: ", threadName,
|
|
|
|
rs_errno_to_condition(pError) );
|
2019-10-31 18:23:38 +01:00
|
|
|
mHasStopped = true;
|
|
|
|
print_stacktrace();
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2020-01-08 14:24:46 +01:00
|
|
|
/* Store an extra copy of thread id for debugging */
|
|
|
|
mLastTid = mTid;
|
|
|
|
|
2020-01-06 14:46:36 +01:00
|
|
|
/* Store thread full name as PThread is not able to keep it entirely */
|
|
|
|
mFullName = threadName;
|
|
|
|
|
|
|
|
/* Set PThread thread name which is restricted to 16 characters
|
|
|
|
* including the terminating null byte */
|
2019-10-31 18:23:38 +01:00
|
|
|
if(pthread_setname_np && !threadName.empty())
|
|
|
|
RS_pthread_setname_np(mTid, threadName.substr(0, 15).c_str());
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
2015-05-22 18:16:49 +00:00
|
|
|
|
2019-10-31 18:23:38 +01:00
|
|
|
RsErr() << __PRETTY_FUNCTION__ << " attempt to start already running thread"
|
|
|
|
<< std::endl;
|
|
|
|
print_stacktrace();
|
|
|
|
return false;
|
2011-03-03 23:30:08 +00:00
|
|
|
}
|
|
|
|
|
2008-07-23 22:01:59 +00:00
|
|
|
RsQueueThread::RsQueueThread(uint32_t min, uint32_t max, double relaxFactor )
|
2015-05-22 18:16:49 +00:00
|
|
|
:mMinSleep(min), mMaxSleep(max), mRelaxFactor(relaxFactor)
|
2008-07-23 22:01:59 +00:00
|
|
|
{
|
2015-05-22 18:16:49 +00:00
|
|
|
mLastSleep = (uint32_t)mMinSleep ;
|
|
|
|
mLastWork = time(NULL) ;
|
2008-07-23 22:01:59 +00:00
|
|
|
}
|
|
|
|
|
2019-10-31 18:23:38 +01:00
|
|
|
void RsQueueThread::threadTick()
|
2008-07-23 22:01:59 +00:00
|
|
|
{
|
2015-05-22 18:16:49 +00:00
|
|
|
bool doneWork = false;
|
|
|
|
while(workQueued() && doWork())
|
|
|
|
{
|
|
|
|
doneWork = true;
|
|
|
|
}
|
2019-10-31 18:23:38 +01:00
|
|
|
time_t now = time(NULL);
|
2015-05-22 18:16:49 +00:00
|
|
|
if (doneWork)
|
|
|
|
{
|
|
|
|
mLastWork = now;
|
|
|
|
mLastSleep = (uint32_t) (mMinSleep + (mLastSleep - mMinSleep) / 2.0);
|
2016-05-12 10:26:38 -04:00
|
|
|
#ifdef DEBUG_TICKING
|
2016-05-04 22:23:36 -04:00
|
|
|
THREAD_DEBUG << "RsQueueThread::data_tick() done work: sleeping for: " << mLastSleep << " ms" << std::endl;
|
2008-11-02 11:38:11 +00:00
|
|
|
#endif
|
|
|
|
|
2015-05-22 18:16:49 +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;
|
|
|
|
}
|
2016-05-12 10:26:38 -04:00
|
|
|
#ifdef DEBUG_TICKING
|
2016-05-04 22:23:36 -04:00
|
|
|
THREAD_DEBUG << "RsQueueThread::data_tick() no work: sleeping for: " << mLastSleep << " ms" << std::endl;
|
2008-11-02 11:38:11 +00:00
|
|
|
#endif
|
2015-05-22 18:16:49 +00:00
|
|
|
}
|
2019-10-31 18:23:38 +01:00
|
|
|
|
|
|
|
std::this_thread::sleep_for(std::chrono::milliseconds(mLastSleep));
|
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()
|
2019-10-31 18:23:38 +01:00
|
|
|
{
|
|
|
|
_thread_id = 0;
|
|
|
|
pthread_mutex_unlock(&realMutex);
|
2014-10-28 20:37:48 +00:00
|
|
|
}
|
|
|
|
|
2011-07-04 22:59:39 +00:00
|
|
|
void RsMutex::lock()
|
|
|
|
{
|
2019-10-31 18:23:38 +01:00
|
|
|
int err = pthread_mutex_lock(&realMutex);
|
|
|
|
if( err != 0)
|
|
|
|
{
|
|
|
|
RsErr() << __PRETTY_FUNCTION__ << "pthread_mutex_lock returned: "
|
2021-11-04 19:17:57 +01:00
|
|
|
<< rs_errno_to_condition(err)
|
2020-12-08 17:15:16 +01:00
|
|
|
#ifdef RS_MUTEX_DEBUG
|
|
|
|
<< " name: " << name()
|
2011-07-04 22:59:39 +00:00
|
|
|
#endif
|
2019-10-31 18:23:38 +01:00
|
|
|
<< std::endl;
|
2013-08-31 08:16:09 +00:00
|
|
|
|
2019-10-31 18:23:38 +01:00
|
|
|
print_stacktrace();
|
2013-08-31 08:16:09 +00:00
|
|
|
|
|
|
|
#ifdef RSMUTEX_ABORT
|
|
|
|
abort();
|
|
|
|
#endif
|
2019-10-31 18:23:38 +01:00
|
|
|
}
|
2013-08-31 08:16:09 +00:00
|
|
|
|
2019-10-31 18:23:38 +01:00
|
|
|
_thread_id = pthread_self();
|
2014-10-28 20:37:48 +00:00
|
|
|
}
|
2019-10-31 18:23:38 +01:00
|
|
|
|
2020-12-08 17:15:16 +01:00
|
|
|
#ifdef RS_MUTEX_DEBUG
|
2014-11-11 19:47:05 +00:00
|
|
|
double RsStackMutex::getCurrentTS()
|
2014-10-28 20:37:48 +00:00
|
|
|
{
|
|
|
|
|
|
|
|
#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
|
|
|
|
|
2014-11-11 19:47:05 +00:00
|
|
|
|
2019-10-31 18:23:38 +01:00
|
|
|
RsThread::~RsThread()
|
|
|
|
{
|
2020-01-08 14:24:46 +01:00
|
|
|
if(!mHasStopped)
|
2019-10-31 18:23:38 +01:00
|
|
|
{
|
2020-01-08 14:24:46 +01:00
|
|
|
RsErr() << __PRETTY_FUNCTION__ << " deleting thread: " << mLastTid
|
|
|
|
<< " " << mFullName << " that is still "
|
2019-10-31 18:23:38 +01:00
|
|
|
<< "running! Something seems very wrong here and RetroShare is "
|
|
|
|
<< "likely to crash because of this." << std::endl;
|
|
|
|
print_stacktrace();
|
|
|
|
|
2021-11-04 19:17:57 +01:00
|
|
|
/* Last resort attempt to stop the thread in a less pathological state.
|
|
|
|
* Don't call fullstop() as it rely on virtual methods that at this
|
|
|
|
* point are not anymore the one from inerithing classes causing
|
|
|
|
* compilers to output a warning */
|
|
|
|
waitWhileStopping();
|
2019-10-31 18:23:38 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
RsQueueThread::~RsQueueThread() = default;
|