2018-07-25 00:35:11 +00:00
|
|
|
#ifndef LLARP_THREADING_HPP
|
|
|
|
#define LLARP_THREADING_HPP
|
2019-03-03 15:01:05 +00:00
|
|
|
|
|
|
|
#include <absl/synchronization/barrier.h>
|
|
|
|
#include <absl/synchronization/mutex.h>
|
2019-09-03 22:25:37 +00:00
|
|
|
#include <absl/types/optional.h>
|
2019-03-03 20:51:47 +00:00
|
|
|
#include <absl/time/time.h>
|
2018-08-12 17:22:29 +00:00
|
|
|
|
2019-09-03 22:25:37 +00:00
|
|
|
#include <iostream>
|
|
|
|
#include <thread>
|
|
|
|
|
2019-07-22 22:20:17 +00:00
|
|
|
#if defined(WIN32) && !defined(__GNUC__)
|
2019-07-17 09:23:46 +00:00
|
|
|
#include <process.h>
|
|
|
|
using pid_t = int;
|
|
|
|
#else
|
|
|
|
#include <sys/types.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
#endif
|
|
|
|
|
2019-09-03 15:56:56 +00:00
|
|
|
#ifdef TRACY_ENABLE
|
|
|
|
#include "Tracy.hpp"
|
|
|
|
#define DECLARE_LOCK(type, var, ...) TracyLockable(type, var)
|
|
|
|
#define ACQUIRE_LOCK(lock, mtx) lock(mtx)
|
|
|
|
#else
|
|
|
|
#define DECLARE_LOCK(type, var, ...) type var __VA_ARGS__
|
|
|
|
#define ACQUIRE_LOCK(lock, mtx) lock(&mtx)
|
|
|
|
#endif
|
|
|
|
|
2018-08-12 17:22:29 +00:00
|
|
|
namespace llarp
|
|
|
|
{
|
|
|
|
namespace util
|
|
|
|
{
|
|
|
|
/// a mutex that does nothing
|
2019-10-14 16:17:08 +00:00
|
|
|
///
|
|
|
|
/// this exists to convert mutexes that were initially in use (but may no
|
|
|
|
/// longer be necessary) into no-op placeholders (except in debug mode
|
|
|
|
/// where they complain loudly when they are actually accessed across
|
2019-10-11 19:50:50 +00:00
|
|
|
/// different threads; see below).
|
2019-10-14 16:17:08 +00:00
|
|
|
///
|
2019-10-11 19:50:50 +00:00
|
|
|
/// the idea is to "turn off" the mutexes and see where they are actually
|
|
|
|
/// needed.
|
2019-03-03 20:51:47 +00:00
|
|
|
struct LOCKABLE NullMutex
|
2018-08-12 17:22:29 +00:00
|
|
|
{
|
2019-09-03 22:25:37 +00:00
|
|
|
#ifdef LOKINET_DEBUG
|
2019-10-11 05:26:55 +00:00
|
|
|
/// in debug mode, we implement lock() to enforce that any lock is only
|
|
|
|
/// used from a single thread. the point of this is to identify locks that
|
|
|
|
/// are actually needed by dying a painful death when used across threads
|
2019-09-03 22:25:37 +00:00
|
|
|
mutable absl::optional< std::thread::id > m_id;
|
|
|
|
void
|
|
|
|
lock() const
|
|
|
|
{
|
|
|
|
if(!m_id)
|
|
|
|
{
|
|
|
|
m_id.emplace(std::this_thread::get_id());
|
|
|
|
}
|
|
|
|
else if(m_id.value() != std::this_thread::get_id())
|
|
|
|
{
|
2019-10-14 16:17:08 +00:00
|
|
|
std::cerr << "NullMutex " << this
|
|
|
|
<< " was used across threads: locked by "
|
2019-09-03 22:25:37 +00:00
|
|
|
<< std::this_thread::get_id()
|
|
|
|
<< " and was previously locked by " << m_id.value() << "\n";
|
2019-10-11 05:26:55 +00:00
|
|
|
// if you're encountering this abort() call, you may have discovered a
|
|
|
|
// case where a NullMutex should be reverted to a "real mutex"
|
2019-09-03 22:25:37 +00:00
|
|
|
std::abort();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
void
|
|
|
|
lock() const
|
|
|
|
{
|
|
|
|
}
|
|
|
|
#endif
|
2018-08-12 17:22:29 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
/// a lock that does nothing
|
2019-03-03 20:51:47 +00:00
|
|
|
struct SCOPED_LOCKABLE NullLock
|
2018-08-12 17:22:29 +00:00
|
|
|
{
|
2019-04-19 18:24:33 +00:00
|
|
|
NullLock(ABSL_ATTRIBUTE_UNUSED const NullMutex* mtx)
|
2019-03-03 20:51:47 +00:00
|
|
|
EXCLUSIVE_LOCK_FUNCTION(mtx)
|
|
|
|
{
|
2019-09-03 22:25:37 +00:00
|
|
|
mtx->lock();
|
2019-03-03 20:51:47 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
~NullLock() UNLOCK_FUNCTION()
|
2018-08-12 17:22:29 +00:00
|
|
|
{
|
2019-07-30 23:42:13 +00:00
|
|
|
(void)this; // trick clang-tidy
|
2018-08-12 17:22:29 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2019-09-03 15:56:56 +00:00
|
|
|
using Mutex = absl::Mutex;
|
|
|
|
using Lock = absl::MutexLock;
|
|
|
|
|
2019-06-26 21:39:29 +00:00
|
|
|
using ReleasableLock = absl::ReleasableMutexLock;
|
|
|
|
using Condition = absl::CondVar;
|
2018-08-12 17:22:29 +00:00
|
|
|
|
2018-11-17 21:07:04 +00:00
|
|
|
class Semaphore
|
|
|
|
{
|
|
|
|
private:
|
2019-03-03 20:51:47 +00:00
|
|
|
Mutex m_mutex; // protects m_count
|
|
|
|
size_t m_count GUARDED_BY(m_mutex);
|
|
|
|
|
|
|
|
bool
|
|
|
|
ready() const SHARED_LOCKS_REQUIRED(m_mutex)
|
|
|
|
{
|
|
|
|
return m_count > 0;
|
|
|
|
}
|
2018-11-17 21:07:04 +00:00
|
|
|
|
|
|
|
public:
|
|
|
|
Semaphore(size_t count) : m_count(count)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2019-03-03 20:51:47 +00:00
|
|
|
notify() LOCKS_EXCLUDED(m_mutex)
|
2018-11-17 21:07:04 +00:00
|
|
|
{
|
2019-03-03 15:01:05 +00:00
|
|
|
Lock lock(&m_mutex);
|
2018-11-17 21:07:04 +00:00
|
|
|
m_count++;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2019-03-03 20:51:47 +00:00
|
|
|
wait() LOCKS_EXCLUDED(m_mutex)
|
2018-11-17 21:07:04 +00:00
|
|
|
{
|
2019-03-03 15:01:05 +00:00
|
|
|
Lock lock(&m_mutex);
|
2019-03-03 20:51:47 +00:00
|
|
|
m_mutex.Await(absl::Condition(this, &Semaphore::ready));
|
2018-11-17 21:07:04 +00:00
|
|
|
|
|
|
|
m_count--;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
2019-03-03 20:51:47 +00:00
|
|
|
waitFor(absl::Duration timeout) LOCKS_EXCLUDED(m_mutex)
|
2018-11-17 21:07:04 +00:00
|
|
|
{
|
2019-03-03 15:01:05 +00:00
|
|
|
Lock lock(&m_mutex);
|
2018-11-17 21:07:04 +00:00
|
|
|
|
2019-03-03 20:51:47 +00:00
|
|
|
if(!m_mutex.AwaitWithTimeout(absl::Condition(this, &Semaphore::ready),
|
|
|
|
timeout))
|
2018-11-17 21:07:04 +00:00
|
|
|
{
|
2019-03-03 20:51:47 +00:00
|
|
|
return false;
|
2018-11-17 21:07:04 +00:00
|
|
|
}
|
|
|
|
|
2019-03-03 15:01:05 +00:00
|
|
|
m_count--;
|
|
|
|
return true;
|
2018-11-17 21:07:04 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2019-03-03 15:01:05 +00:00
|
|
|
using Barrier = absl::Barrier;
|
|
|
|
|
2019-07-09 00:06:22 +00:00
|
|
|
void
|
|
|
|
SetThreadName(const std::string& name);
|
|
|
|
|
2019-07-17 09:23:46 +00:00
|
|
|
inline pid_t
|
|
|
|
GetPid()
|
|
|
|
{
|
|
|
|
#ifdef WIN32
|
|
|
|
return _getpid();
|
|
|
|
#else
|
|
|
|
return ::getpid();
|
2019-07-17 19:35:49 +00:00
|
|
|
#endif
|
2019-07-17 09:23:46 +00:00
|
|
|
}
|
2019-11-14 18:50:45 +00:00
|
|
|
|
|
|
|
// type for detecting contention on a resource
|
|
|
|
struct ContentionKiller
|
|
|
|
{
|
2019-11-19 19:16:22 +00:00
|
|
|
template < typename F >
|
2019-11-14 18:50:45 +00:00
|
|
|
void
|
2019-11-19 19:16:22 +00:00
|
|
|
TryAccess(F visit) const
|
|
|
|
{
|
|
|
|
NullLock lock(&__access);
|
|
|
|
visit();
|
|
|
|
}
|
2019-11-14 18:50:45 +00:00
|
|
|
|
|
|
|
private:
|
|
|
|
mutable NullMutex __access;
|
|
|
|
};
|
2018-08-12 17:22:29 +00:00
|
|
|
} // namespace util
|
|
|
|
} // namespace llarp
|
|
|
|
|
2018-08-16 14:34:15 +00:00
|
|
|
#endif
|