add mingw stl threading lib

run make format
pull/7/head
Jeff Becker 6 years ago
parent f222f002f4
commit f9db26adee

@ -53,7 +53,7 @@ main(int argc, char *argv[])
struct dnsd_context dnsd;
if(!llarp_dnsd_init(&dnsd, netloop, "*", 1053, SERVER, PORT))
{
//llarp::LogError("failed to initialize dns subsystem");
// llarp::LogError("failed to initialize dns subsystem");
llarp::LogError("Couldnt init dns daemon");
return 0;
}

@ -2,10 +2,11 @@
#define LLARP_CODEL_QUEUE_HPP
#include <llarp/time.h>
#include <llarp/logger.hpp>
#include <llarp/threading.hpp>
#include <cmath>
#include <functional>
#include <mutex>
#include <queue>
#include <string>

@ -1,9 +1,9 @@
#ifndef LLARP_DNS_H_
#define LLARP_DNS_H_
#include <llarp/ev.h> // for sockaadr
#include <llarp/ev.h> // for sockaadr
#include <sys/types.h> // for uint & ssize_t
#include <map> // for udp DNS tracker
#include <map> // for udp DNS tracker
#ifdef __cplusplus
extern "C"
@ -16,14 +16,14 @@ extern "C"
*/
//#include <mutex>
//typedef std::mutex mtx_t;
//typedef std::lock_guard< mtx_t > lock_t;
// typedef std::mutex mtx_t;
// typedef std::lock_guard< mtx_t > lock_t;
// fwd declr
//struct dns_query;
// struct dns_query;
struct dnsc_context;
struct dnsd_context;
//struct dnsd_question_request;
// struct dnsd_question_request;
struct dnsc_answer_request;
// dnsc can work over any UDP socket
@ -34,12 +34,12 @@ extern "C"
struct dns_tracker
{
//uint c_responses;
// uint c_responses;
uint c_requests;
std::map< uint, dnsc_answer_request * > client_request;
// FIXME: support multiple dns server contexts
dnsd_context *dnsd;
//std::map< uint, dnsd_question_request * > daemon_request;
// std::map< uint, dnsd_question_request * > daemon_request;
};
// should we pass by llarp::Addr

@ -1,5 +1,6 @@
#pragma once
#include <llarp/threading.hpp>
#include "llarp/iwp.h"
#include "llarp/iwp/establish_job.hpp"
#include "router.hpp"
@ -8,7 +9,6 @@
#include <algorithm>
#include <fstream>
#include <mutex>
struct llarp_link
{

@ -5,7 +5,7 @@
#include <ctime>
#include <iomanip>
#include <iostream>
#include <mutex>
#include <llarp/threading.hpp>
#include <sstream>
#include <string>

@ -15,11 +15,11 @@
#include <llarp/routing/handler.hpp>
#include <llarp/routing/message.hpp>
#include <llarp/service/Intro.hpp>
#include <llarp/threading.hpp>
#include <functional>
#include <list>
#include <map>
#include <mutex>
#include <unordered_map>
#include <vector>

@ -0,0 +1,12 @@
#ifndef LLARP_THREADING_HPP
#define LLARP_THREADING_HPP
#include <mutex>
#if defined(__MINGW32__)
#include <llarp/win32/threads/mingw.condition_variable.h>
#include <llarp/win32/threads/mingw.mutex.h>
#include <llarp/win32/threads/mingw.thread.h>
#else
#include <condition_variable>
#include <thread>
#endif
#endif

@ -0,0 +1,603 @@
/**
* @file condition_variable.h
* @brief std::condition_variable implementation for MinGW
*
* (c) 2013-2016 by Mega Limited, Auckland, New Zealand
* @author Alexander Vassilev
*
* @copyright Simplified (2-clause) BSD License.
* You should have received a copy of the license along with this
* program.
*
* This code 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.
* @note
* This file may become part of the mingw-w64 runtime package. If/when this
* happens, the appropriate license will be added, i.e. this code will become
* dual-licensed, and the current BSD 2-clause license will stay.
*/
#ifndef MINGW_CONDITIONAL_VARIABLE_H
#define MINGW_CONDITIONAL_VARIABLE_H
#if !defined(__cplusplus) || (__cplusplus < 201103L)
#error A C++11 compiler is required!
#endif
// Use the standard classes for std::, if available.
#include <condition_variable>
#include <windows.h>
#include <atomic>
#include <cassert>
#include <chrono>
#include <system_error>
#include "mingw.mutex.h"
#include "mingw.shared_mutex.h"
namespace mingw_stdthread
{
#if defined(__MINGW32__) && !defined(_GLIBCXX_HAS_GTHREADS)
enum class cv_status
{
no_timeout,
timeout
};
#else
using std::cv_status;
#endif
namespace xp
{
// Include the XP-compatible condition_variable classes only if actually
// compiling for XP. The XP-compatible classes are slower than the newer
// versions, and depend on features not compatible with Windows Phone 8.
#if(WINVER < _WIN32_WINNT_VISTA)
class condition_variable_any
{
protected:
recursive_mutex mMutex;
std::atomic< int > mNumWaiters;
HANDLE mSemaphore;
HANDLE mWakeEvent;
public:
typedef HANDLE native_handle_type;
native_handle_type
native_handle()
{
return mSemaphore;
}
condition_variable_any(const condition_variable_any&) = delete;
condition_variable_any&
operator=(const condition_variable_any&) = delete;
condition_variable_any()
: mMutex()
, mNumWaiters(0)
, mSemaphore(CreateSemaphore(NULL, 0, 0xFFFF, NULL))
, mWakeEvent(CreateEvent(NULL, FALSE, FALSE, NULL))
{
}
~condition_variable_any()
{
CloseHandle(mWakeEvent);
CloseHandle(mSemaphore);
}
protected:
template < class M >
bool
wait_impl(M& lock, DWORD timeout)
{
{
lock_guard< recursive_mutex > guard(mMutex);
mNumWaiters++;
}
lock.unlock();
DWORD ret = WaitForSingleObject(mSemaphore, timeout);
mNumWaiters--;
SetEvent(mWakeEvent);
lock.lock();
if(ret == WAIT_OBJECT_0)
return true;
else if(ret == WAIT_TIMEOUT)
return false;
// 2 possible cases:
// 1)The point in notify_all() where we determine the count to
// increment the semaphore with has not been reached yet:
// we just need to decrement mNumWaiters, but setting the event does not
// hurt
//
// 2)Semaphore has just been released with mNumWaiters just before
// we decremented it. This means that the semaphore count
// after all waiters finish won't be 0 - because not all waiters
// woke up by acquiring the semaphore - we woke up by a timeout.
// The notify_all() must handle this grafecully
//
else
{
using namespace std;
throw system_error(make_error_code(errc::protocol_error));
}
}
public:
template < class M >
void
wait(M& lock)
{
wait_impl(lock, INFINITE);
}
template < class M, class Predicate >
void
wait(M& lock, Predicate pred)
{
while(!pred())
{
wait(lock);
};
}
void
notify_all() noexcept
{
lock_guard< recursive_mutex > lock(
mMutex); // block any further wait requests until all current
// waiters are unblocked
if(mNumWaiters.load() <= 0)
return;
ReleaseSemaphore(mSemaphore, mNumWaiters, NULL);
while(mNumWaiters > 0)
{
auto ret = WaitForSingleObject(mWakeEvent, 1000);
if(ret == WAIT_FAILED || ret == WAIT_ABANDONED)
std::terminate();
}
assert(mNumWaiters == 0);
// in case some of the waiters timed out just after we released the
// semaphore by mNumWaiters, it won't be zero now, because not all
// waiters woke up by acquiring the semaphore. So we must zero the
// semaphore before we accept waiters for the next event See _wait_impl
// for details
while(WaitForSingleObject(mSemaphore, 0) == WAIT_OBJECT_0)
;
}
void
notify_one() noexcept
{
lock_guard< recursive_mutex > lock(mMutex);
int targetWaiters = mNumWaiters.load() - 1;
if(targetWaiters <= -1)
return;
ReleaseSemaphore(mSemaphore, 1, NULL);
while(mNumWaiters > targetWaiters)
{
auto ret = WaitForSingleObject(mWakeEvent, 1000);
if(ret == WAIT_FAILED || ret == WAIT_ABANDONED)
std::terminate();
}
assert(mNumWaiters == targetWaiters);
}
template < class M, class Rep, class Period >
cv_status
wait_for(M& lock, const std::chrono::duration< Rep, Period >& rel_time)
{
using namespace std::chrono;
long long timeout = duration_cast< milliseconds >(rel_time).count();
if(timeout < 0)
timeout = 0;
bool ret = wait_impl(lock, (DWORD)timeout);
return ret ? cv_status::no_timeout : cv_status::timeout;
}
template < class M, class Rep, class Period, class Predicate >
bool
wait_for(M& lock, const std::chrono::duration< Rep, Period >& rel_time,
Predicate pred)
{
return wait_until(lock, std::chrono::steady_clock::now() + rel_time,
pred);
}
template < class M, class Clock, class Duration >
cv_status
wait_until(M& lock,
const std::chrono::time_point< Clock, Duration >& abs_time)
{
return wait_for(lock, abs_time - Clock::now());
}
template < class M, class Clock, class Duration, class Predicate >
bool
wait_until(M& lock,
const std::chrono::time_point< Clock, Duration >& abs_time,
Predicate pred)
{
while(!pred())
{
if(wait_until(lock, abs_time) == cv_status::timeout)
{
return pred();
}
}
return true;
}
};
class condition_variable : protected condition_variable_any
{
protected:
typedef condition_variable_any base;
public:
using base::base;
using base::native_handle;
using base::native_handle_type;
using base::notify_all;
using base::notify_one;
void
wait(unique_lock< mutex >& lock)
{
base::wait(lock);
}
template < class Predicate >
void
wait(unique_lock< mutex >& lock, Predicate pred)
{
base::wait(lock, pred);
}
template < class Rep, class Period >
cv_status
wait_for(unique_lock< mutex >& lock,
const std::chrono::duration< Rep, Period >& rel_time)
{
return base::wait_for(lock, rel_time);
}
template < class Rep, class Period, class Predicate >
bool
wait_for(unique_lock< mutex >& lock,
const std::chrono::duration< Rep, Period >& rel_time,
Predicate pred)
{
return base::wait_for(lock, rel_time, pred);
}
template < class Clock, class Duration >
cv_status
wait_until(unique_lock< mutex >& lock,
const std::chrono::time_point< Clock, Duration >& abs_time)
{
return base::wait_until(lock, abs_time);
}
template < class Clock, class Duration, class Predicate >
bool
wait_until(unique_lock< mutex >& lock,
const std::chrono::time_point< Clock, Duration >& abs_time,
Predicate pred)
{
return base::wait_until(lock, abs_time, pred);
}
};
#endif // Compiling for XP
} // namespace xp
#if(WINVER >= _WIN32_WINNT_VISTA)
namespace vista
{
// If compiling for Vista or higher, use the native condition variable.
class condition_variable
{
protected:
CONDITION_VARIABLE cvariable_;
#if STDMUTEX_RECURSION_CHECKS
template < typename MTX >
inline static void
before_wait(MTX* pmutex)
{
pmutex->mOwnerThread.checkSetOwnerBeforeUnlock();
}
template < typename MTX >
inline static void
after_wait(MTX* pmutex)
{
pmutex->mOwnerThread.setOwnerAfterLock(GetCurrentThreadId());
}
#else
inline static void
before_wait(void*)
{
}
inline static void
after_wait(void*)
{
}
#endif
bool
wait_impl(unique_lock< xp::mutex >& lock, DWORD time)
{
static_assert(std::is_same< typename xp::mutex::native_handle_type,
PCRITICAL_SECTION >::value,
"Native Win32 condition variable requires std::mutex to \
use native Win32 critical section objects.");
xp::mutex* pmutex = lock.release();
before_wait(pmutex);
BOOL success = SleepConditionVariableCS(&cvariable_,
pmutex->native_handle(), time);
after_wait(pmutex);
lock = unique_lock< xp::mutex >(*pmutex, adopt_lock);
return success;
}
bool
wait_unique(windows7::mutex* pmutex, DWORD time)
{
before_wait(pmutex);
BOOL success = SleepConditionVariableSRW(
native_handle(), pmutex->native_handle(), time, 0);
after_wait(pmutex);
return success;
}
bool
wait_impl(unique_lock< windows7::mutex >& lock, DWORD time)
{
windows7::mutex* pmutex = lock.release();
bool success = wait_unique(pmutex, time);
lock = unique_lock< windows7::mutex >(*pmutex, adopt_lock);
return success;
}
public:
typedef PCONDITION_VARIABLE native_handle_type;
native_handle_type
native_handle(void)
{
return &cvariable_;
}
condition_variable(void) : cvariable_()
{
InitializeConditionVariable(&cvariable_);
}
~condition_variable(void) = default;
condition_variable(const condition_variable&) = delete;
condition_variable&
operator=(const condition_variable&) = delete;
void
notify_one(void) noexcept
{
WakeConditionVariable(&cvariable_);
}
void
notify_all(void) noexcept
{
WakeAllConditionVariable(&cvariable_);
}
void
wait(unique_lock< mutex >& lock)
{
wait_impl(lock, INFINITE);
}
template < class Predicate >
void
wait(unique_lock< mutex >& lock, Predicate pred)
{
while(!pred())
wait(lock);
}
template < class Rep, class Period >
cv_status
wait_for(unique_lock< mutex >& lock,
const std::chrono::duration< Rep, Period >& rel_time)
{
using namespace std::chrono;
auto time = duration_cast< milliseconds >(rel_time).count();
if(time < 0)
time = 0;
bool result = wait_impl(lock, static_cast< DWORD >(time));
return result ? cv_status::no_timeout : cv_status::timeout;
}
template < class Rep, class Period, class Predicate >
bool
wait_for(unique_lock< mutex >& lock,
const std::chrono::duration< Rep, Period >& rel_time,
Predicate pred)
{
return wait_until(lock, std::chrono::steady_clock::now() + rel_time,
std::move(pred));
}
template < class Clock, class Duration >
cv_status
wait_until(unique_lock< mutex >& lock,
const std::chrono::time_point< Clock, Duration >& abs_time)
{
return wait_for(lock, abs_time - Clock::now());
}
template < class Clock, class Duration, class Predicate >
bool
wait_until(unique_lock< mutex >& lock,
const std::chrono::time_point< Clock, Duration >& abs_time,
Predicate pred)
{
while(!pred())
{
if(wait_until(lock, abs_time) == cv_status::timeout)
{
return pred();
}
}
return true;
}
};
class condition_variable_any : protected condition_variable
{
protected:
typedef condition_variable base;
typedef windows7::shared_mutex native_shared_mutex;
// When available, the SRW-based mutexes should be faster than the
// CriticalSection-based mutexes. Only try_lock will be unavailable in
// Vista, and try_lock is not used by condition_variable_any.
windows7::mutex internal_mutex_;
template < class L >
bool
wait_impl(L& lock, DWORD time)
{
unique_lock< decltype(internal_mutex_) > internal_lock(internal_mutex_);
lock.unlock();
bool success = base::wait_impl(internal_lock, time);
lock.lock();
return success;
}
// If the lock happens to be called on a native Windows mutex, skip any
// extra
// contention.
inline bool
wait_impl(unique_lock< mutex >& lock, DWORD time)
{
return base::wait_impl(lock, time);
}
// Some shared_mutex functionality is available even in Vista, but it's
// not
// until Windows 7 that a full implementation is natively possible. The
// class itself is defined, with missing features, at the Vista feature
// level.
static_assert(CONDITION_VARIABLE_LOCKMODE_SHARED != 0,
"The flag \
CONDITION_VARIABLE_LOCKMODE_SHARED is not defined as expected. The value for \
exclusive mode is unknown (not specified by Microsoft Dev Center), but assumed \
to be 0. There is a conflict with CONDITION_VARIABLE_LOCKMODE_SHARED.");
//#if (WINVER >= _WIN32_WINNT_VISTA)
bool
wait_impl(unique_lock< native_shared_mutex >& lock, DWORD time)
{
native_shared_mutex* pmutex = lock.release();
bool success = wait_unique(pmutex, time);
lock = unique_lock< native_shared_mutex >(*pmutex, adopt_lock);
return success;
}
bool
wait_impl(shared_lock< native_shared_mutex >& lock, DWORD time)
{
native_shared_mutex* pmutex = lock.release();
BOOL success = SleepConditionVariableSRW(
base::native_handle(), pmutex->native_handle(), time,
CONDITION_VARIABLE_LOCKMODE_SHARED);
lock = shared_lock< native_shared_mutex >(*pmutex, adopt_lock);
return success;
}
//#endif
public:
typedef typename base::native_handle_type native_handle_type;
using base::native_handle;
condition_variable_any(void) : base(), internal_mutex_()
{
}
~condition_variable_any(void) = default;
using base::notify_all;
using base::notify_one;
template < class L >
void
wait(L& lock)
{
wait_impl(lock, INFINITE);
}
template < class L, class Predicate >
void
wait(L& lock, Predicate pred)
{
while(!pred())
wait(lock);
}
template < class L, class Rep, class Period >
cv_status
wait_for(L& lock, const std::chrono::duration< Rep, Period >& period)
{
using namespace std::chrono;
auto time = duration_cast< milliseconds >(period).count();
if(time < 0)
time = 0;
bool result = wait_impl(lock, static_cast< DWORD >(time));
return result ? cv_status::no_timeout : cv_status::timeout;
}
template < class L, class Rep, class Period, class Predicate >
bool
wait_for(L& lock, const std::chrono::duration< Rep, Period >& period,
Predicate pred)
{
return wait_until(lock, std::chrono::steady_clock::now() + period,
std::move(pred));
}
template < class L, class Clock, class Duration >
cv_status
wait_until(L& lock,
const std::chrono::time_point< Clock, Duration >& abs_time)
{
return wait_for(lock, abs_time - Clock::now());
}
template < class L, class Clock, class Duration, class Predicate >
bool
wait_until(L& lock,
const std::chrono::time_point< Clock, Duration >& abs_time,
Predicate pred)
{
while(!pred())
{
if(wait_until(lock, abs_time) == cv_status::timeout)
{
return pred();
}
}
return true;
}
};
} // Namespace vista
#endif
#if WINVER < 0x0600
using xp::condition_variable;
using xp::condition_variable_any;
#else
using vista::condition_variable;
using vista::condition_variable_any;
#endif
} // Namespace mingw_stdthread
// Push objects into std, but only if they are not already there.
namespace std
{
// Because of quirks of the compiler, the common "using namespace std;"
// directive would flatten the namespaces and introduce ambiguity where there
// was none. Direct specification (std::), however, would be unaffected.
// Take the safe option, and include only in the presence of MinGW's win32
// implementation.
#if defined(__MINGW32__) && !defined(_GLIBCXX_HAS_GTHREADS)
using mingw_stdthread::condition_variable;
using mingw_stdthread::condition_variable_any;
using mingw_stdthread::cv_status;
#elif !defined(MINGW_STDTHREAD_REDUNDANCY_WARNING) // Skip repetition
#define MINGW_STDTHREAD_REDUNDANCY_WARNING
#pragma message \
"This version of MinGW seems to include a win32 port of\
pthreads, and probably already has C++11 std threading classes implemented,\
based on pthreads. These classes, found in namespace std, are not overridden\
by the mingw-std-thread library. If you would still like to use this\
implementation (as it is more lightweight), use the classes provided in\
namespace mingw_stdthread."
#endif
} // namespace std
#endif // MINGW_CONDITIONAL_VARIABLE_H

@ -0,0 +1,522 @@
/**
* @file mingw.mutex.h
* @brief std::mutex et al implementation for MinGW
** (c) 2013-2016 by Mega Limited, Auckland, New Zealand
* @author Alexander Vassilev
*
* @copyright Simplified (2-clause) BSD License.
* You should have received a copy of the license along with this
* program.
*
* This code 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.
* @note
* This file may become part of the mingw-w64 runtime package. If/when this
*happens, the appropriate license will be added, i.e. this code will become
*dual-licensed, and the current BSD 2-clause license will stay.
*/
#ifndef WIN32STDMUTEX_H
#define WIN32STDMUTEX_H
#if !defined(__cplusplus) || (__cplusplus < 201103L)
#error A C++11 compiler is required!
#endif
// Recursion checks on non-recursive locks have some performance penalty, and
// the C++ standard does not mandate them. The user might want to explicitly
// enable or disable such checks. If the user has no preference, enable such
// checks in debug builds, but not in release builds.
#ifdef STDMUTEX_RECURSION_CHECKS
#elif defined(NDEBUG)
#define STDMUTEX_RECURSION_CHECKS 0
#else
#define STDMUTEX_RECURSION_CHECKS 1
#endif
#include <windows.h>
#include <atomic>
#include <cassert>
#include <chrono>
#include <cstdio>
#include <mutex> //need for call_once()
#include <system_error>
// Need for yield in spinlock and the implementation of invoke
#include "mingw.thread.h"
namespace mingw_stdthread
{
// The _NonRecursive class has mechanisms that do not play nice with direct
// manipulation of the native handle. This forward declaration is part of
// a friend class declaration.
#if STDMUTEX_RECURSION_CHECKS
namespace vista
{
class condition_variable;
}
#endif
// To make this namespace equivalent to the thread-related subset of std,
// pull in the classes and class templates supplied by std but not by this
// implementation.
using std::adopt_lock;
using std::adopt_lock_t;
using std::defer_lock;
using std::defer_lock_t;
using std::lock_guard;
using std::try_to_lock;
using std::try_to_lock_t;
using std::unique_lock;
class recursive_mutex
{
CRITICAL_SECTION mHandle;
public:
typedef LPCRITICAL_SECTION native_handle_type;
native_handle_type
native_handle()
{
return &mHandle;
}
recursive_mutex() noexcept : mHandle()
{
InitializeCriticalSection(&mHandle);
}
recursive_mutex(const recursive_mutex&) = delete;
recursive_mutex&
operator=(const recursive_mutex&) = delete;
~recursive_mutex() noexcept
{
DeleteCriticalSection(&mHandle);
}
void
lock()
{
EnterCriticalSection(&mHandle);
}
void
unlock()
{
LeaveCriticalSection(&mHandle);
}
bool
try_lock()
{
return (TryEnterCriticalSection(&mHandle) != 0);
}
};
#if STDMUTEX_RECURSION_CHECKS
struct _OwnerThread
{
// If this is to be read before locking, then the owner-thread variable
// must
// be atomic to prevent a torn read from spuriously causing errors.
std::atomic< DWORD > mOwnerThread;
constexpr _OwnerThread() noexcept : mOwnerThread(0)
{
}
static void
on_deadlock(void)
{
using namespace std;
fprintf(stderr,
"FATAL: Recursive locking of non-recursive mutex\
detected. Throwing system exception\n");
fflush(stderr);
throw system_error(make_error_code(errc::resource_deadlock_would_occur));
}
DWORD
checkOwnerBeforeLock() const
{
DWORD self = GetCurrentThreadId();
if(mOwnerThread.load(std::memory_order_relaxed) == self)
on_deadlock();
return self;
}
void
setOwnerAfterLock(DWORD id)
{
mOwnerThread.store(id, std::memory_order_relaxed);
}
void
checkSetOwnerBeforeUnlock()
{
DWORD self = GetCurrentThreadId();
if(mOwnerThread.load(std::memory_order_relaxed) != self)
on_deadlock();
mOwnerThread.store(0, std::memory_order_relaxed);
}
};
#endif
// Though the Slim Reader-Writer (SRW) locks used here are not complete until
// Windows 7, implementing partial functionality in Vista will simplify the
// interaction with condition variables.
#if defined(_WIN32) && (WINVER >= _WIN32_WINNT_VISTA)
namespace windows7
{
class mutex
{
SRWLOCK mHandle;
// Track locking thread for error checking.
#if STDMUTEX_RECURSION_CHECKS
friend class vista::condition_variable;
_OwnerThread mOwnerThread;
#endif
public:
typedef PSRWLOCK native_handle_type;
constexpr mutex() noexcept
: mHandle(SRWLOCK_INIT)
#if STDMUTEX_RECURSION_CHECKS
, mOwnerThread()
#endif
{
}
mutex(const mutex&) = delete;
mutex&
operator=(const mutex&) = delete;
void
lock(void)
{
#if STDMUTEX_RECURSION_CHECKS
DWORD self = mOwnerThread.checkOwnerBeforeLock();
#endif
AcquireSRWLockExclusive(&mHandle);
#if STDMUTEX_RECURSION_CHECKS
mOwnerThread.setOwnerAfterLock(self);
#endif
}
void
unlock(void)
{
#if STDMUTEX_RECURSION_CHECKS
mOwnerThread.checkSetOwnerBeforeUnlock();
#endif
ReleaseSRWLockExclusive(&mHandle);
}
// TryAcquireSRW functions are a Windows 7 feature.
#if(WINVER >= _WIN32_WINNT_WIN7)
bool
try_lock(void)
{
#if STDMUTEX_RECURSION_CHECKS
DWORD self = mOwnerThread.checkOwnerBeforeLock();
#endif
BOOL ret = TryAcquireSRWLockExclusive(&mHandle);
#if STDMUTEX_RECURSION_CHECKS
if(ret)
mOwnerThread.setOwnerAfterLock(self);
#endif
return ret;
}
#endif
native_handle_type
native_handle(void)
{
return &mHandle;
}
};
} // Namespace windows7
#endif // Compiling for Vista
namespace xp
{
class mutex
{
CRITICAL_SECTION mHandle;
std::atomic_uchar mState;
// Track locking thread for error checking.
#if STDMUTEX_RECURSION_CHECKS
friend class vista::condition_variable;
_OwnerThread mOwnerThread;
#endif
public:
typedef PCRITICAL_SECTION native_handle_type;
constexpr mutex() noexcept
: mHandle()
, mState(2)
#if STDMUTEX_RECURSION_CHECKS
, mOwnerThread()
#endif
{
}
mutex(const mutex&) = delete;
mutex&
operator=(const mutex&) = delete;
~mutex() noexcept
{
DeleteCriticalSection(&mHandle);
}
void
lock(void)
{
unsigned char state = mState.load(std::memory_order_acquire);
while(state)
{
if((state == 2)
&& mState.compare_exchange_weak(state, 1,
std::memory_order_acquire))
{
InitializeCriticalSection(&mHandle);
mState.store(0, std::memory_order_release);
break;
}
if(state == 1)
{
this_thread::yield();
state = mState.load(std::memory_order_acquire);
}
}
#if STDMUTEX_RECURSION_CHECKS
DWORD self = mOwnerThread.checkOwnerBeforeLock();
#endif
EnterCriticalSection(&mHandle);
#if STDMUTEX_RECURSION_CHECKS
mOwnerThread.setOwnerAfterLock(self);
#endif
}
void
unlock(void)
{
assert(mState.load(std::memory_order_relaxed) == 0);
#if STDMUTEX_RECURSION_CHECKS
mOwnerThread.checkSetOwnerBeforeUnlock();
#endif
LeaveCriticalSection(&mHandle);
}
bool
try_lock(void)
{
unsigned char state = mState.load(std::memory_order_acquire);
if((state == 2)
&& mState.compare_exchange_strong(state, 1,
std::memory_order_acquire))
{
InitializeCriticalSection(&mHandle);
mState.store(0, std::memory_order_release);
}
if(state == 1)
return false;
#if STDMUTEX_RECURSION_CHECKS
DWORD self = mOwnerThread.checkOwnerBeforeLock();
#endif
BOOL ret = TryEnterCriticalSection(&mHandle);
#if STDMUTEX_RECURSION_CHECKS
if(ret)
mOwnerThread.setOwnerAfterLock(self);
#endif
return ret;
}
native_handle_type
native_handle(void)
{
return &mHandle;
}
};
} // namespace xp
#if(WINVER >= _WIN32_WINNT_WIN7)
using windows7::mutex;
#else
using xp::mutex;
#endif
class recursive_timed_mutex
{
bool
try_lock_internal(DWORD ms)
{
DWORD ret = WaitForSingleObject(mHandle, ms);
using namespace std;
switch(ret)
{
case WAIT_TIMEOUT:
return false;
case WAIT_OBJECT_0:
return true;
case WAIT_ABANDONED:
throw system_error(make_error_code(errc::owner_dead));
default:
throw system_error(make_error_code(errc::protocol_error));
}
}
protected:
HANDLE mHandle;
// Track locking thread for error checking of non-recursive timed_mutex. For
// standard compliance, this must be defined in same class and at the same
// access-control level as every other variable in the timed_mutex.
#if STDMUTEX_RECURSION_CHECKS
friend class vista::condition_variable;
_OwnerThread mOwnerThread;
#endif
public:
typedef HANDLE native_handle_type;
native_handle_type
native_handle() const
{
return mHandle;
}
recursive_timed_mutex(const recursive_timed_mutex&) = delete;
recursive_timed_mutex&
operator=(const recursive_timed_mutex&) = delete;
recursive_timed_mutex()
: mHandle(CreateMutex(NULL, FALSE, NULL))
#if STDMUTEX_RECURSION_CHECKS
, mOwnerThread()
#endif
{
}
~recursive_timed_mutex()
{
CloseHandle(mHandle);
}
void
lock()
{
try_lock_internal(INFINITE);
}
void
unlock()
{
using namespace std;
if(!ReleaseMutex(mHandle))
throw system_error(
make_error_code(errc::resource_deadlock_would_occur));
}
bool
try_lock()
{
return try_lock_internal(0);
}
template < class Rep, class Period >
bool
try_lock_for(const std::chrono::duration< Rep, Period >& dur)
{
using namespace std::chrono;
DWORD timeout = (DWORD)duration_cast< milliseconds >(dur).count();
return try_lock_internal(timeout);
}
template < class Clock, class Duration >
bool
try_lock_until(
const std::chrono::time_point< Clock, Duration >& timeout_time)
{
return try_lock_for(timeout_time - Clock::now());
}
};
// Override if, and only if, it is necessary for error-checking.
#if STDMUTEX_RECURSION_CHECKS
class timed_mutex : recursive_timed_mutex
{
public:
timed_mutex(const timed_mutex&) = delete;
timed_mutex&
operator=(const timed_mutex&) = delete;
void
lock()
{
DWORD self = mOwnerThread.checkOwnerBeforeLock();
recursive_timed_mutex::lock();
mOwnerThread.setOwnerAfterLock(self);
}
void
unlock()
{
mOwnerThread.checkSetOwnerBeforeUnlock();
recursive_timed_mutex::unlock();
}
template < class Rep, class Period >
bool
try_lock_for(const std::chrono::duration< Rep, Period >& dur)
{
DWORD self = mOwnerThread.checkOwnerBeforeLock();
bool ret = recursive_timed_mutex::try_lock_for(dur);
if(ret)
mOwnerThread.setOwnerAfterLock(self);
return ret;
}
template < class Clock, class Duration >
bool
try_lock_until(
const std::chrono::time_point< Clock, Duration >& timeout_time)
{
return try_lock_for(timeout_time - Clock::now());
}
bool
try_lock()
{
return try_lock_for(std::chrono::milliseconds(0));
}
};
#else
typedef recursive_timed_mutex timed_mutex;
#endif
class once_flag
{
// When available, the SRW-based mutexes should be faster than the
// CriticalSection-based mutexes. Only try_lock will be unavailable in Vista,
// and try_lock is not used by once_flag.
#if(_WIN32_WINNT == _WIN32_WINNT_VISTA)
windows7::mutex mMutex;
#else
mutex mMutex;
#endif
std::atomic_bool mHasRun;
once_flag(const once_flag&) = delete;
once_flag&
operator=(const once_flag&) = delete;
template < class Callable, class... Args >
friend void
call_once(once_flag& once, Callable&& f, Args&&... args);
public:
constexpr once_flag() noexcept : mMutex(), mHasRun(false)
{
}
};
template < class Callable, class... Args >
void
call_once(once_flag& flag, Callable&& func, Args&&... args)
{
if(flag.mHasRun.load(std::memory_order_acquire))
return;
lock_guard< decltype(flag.mMutex) > lock(flag.mMutex);
if(flag.mHasRun.load(std::memory_order_acquire))
return;
detail::invoke(std::forward< Callable >(func),
std::forward< Args >(args)...);
flag.mHasRun.store(true, std::memory_order_release);
}
} // Namespace mingw_stdthread
// Push objects into std, but only if they are not already there.
namespace std
{
// Because of quirks of the compiler, the common "using namespace std;"
// directive would flatten the namespaces and introduce ambiguity where there
// was none. Direct specification (std::), however, would be unaffected.
// Take the safe option, and include only in the presence of MinGW's win32
// implementation.
#if defined(__MINGW32__) && !defined(_GLIBCXX_HAS_GTHREADS)
using mingw_stdthread::call_once;
using mingw_stdthread::mutex;
using mingw_stdthread::once_flag;
using mingw_stdthread::recursive_mutex;
using mingw_stdthread::recursive_timed_mutex;
using mingw_stdthread::timed_mutex;
#elif !defined(MINGW_STDTHREAD_REDUNDANCY_WARNING) // Skip repetition
#define MINGW_STDTHREAD_REDUNDANCY_WARNING
#pragma message \
"This version of MinGW seems to include a win32 port of\
pthreads, and probably already has C++11 std threading classes implemented,\
based on pthreads. These classes, found in namespace std, are not overridden\
by the mingw-std-thread library. If you would still like to use this\
implementation (as it is more lightweight), use the classes provided in\
namespace mingw_stdthread."
#endif
} // namespace std
#endif // WIN32STDMUTEX_H

@ -0,0 +1,536 @@
/// \file mingw.shared_mutex.h
/// \brief Standard-compliant shared_mutex for MinGW
///
/// (c) 2017 by Nathaniel J. McClatchey, Athens OH, United States
/// \author Nathaniel J. McClatchey
///
/// \copyright Simplified (2-clause) BSD License.
///
/// \note This file may become part of the mingw-w64 runtime package. If/when
/// this happens, the appropriate license will be added, i.e. this code will
/// become dual-licensed, and the current BSD 2-clause license will stay.
/// \note Target Windows version is determined by WINVER, which is determined in
/// <windows.h> from _WIN32_WINNT, which can itself be set by the user.
// Notes on the namespaces:
// - The implementation can be accessed directly in the namespace
// mingw_stdthread.
// - Objects will be brought into namespace std by a using directive. This
// will cause objects declared in std (such as MinGW's implementation) to
// hide this implementation's definitions.
// - To avoid poluting the namespace with implementation details, all objects
// to be pushed into std will be placed in mingw_stdthread::visible.
// The end result is that if MinGW supplies an object, it is automatically
// used. If MinGW does not supply an object, this implementation's version will
// instead be used.
#ifndef MINGW_SHARED_MUTEX_H_
#define MINGW_SHARED_MUTEX_H_
#if !defined(__cplusplus) || (__cplusplus < 201103L)
#error A C++11 compiler is required!
#endif
#include <cassert>
// Use MinGW's shared_lock class template, if it's available. Requires C++14.
// If unavailable (eg. because this library is being used in C++11), then an
// implementation of shared_lock is provided by this header.
#if(__cplusplus >= 201402L)
#include <shared_mutex>
#endif
// For defer_lock_t, adopt_lock_t, and try_to_lock_t
#include "mingw.mutex.h"
// For descriptive errors.
#include <system_error>
// Implementing a shared_mutex without OS support will require atomic read-
// modify-write capacity.
#include <atomic>
// For timing in shared_lock and shared_timed_mutex.
#include <chrono>
// For this_thread::yield.
#include "mingw.thread.h"
// Might be able to use native Slim Reader-Writer (SRW) locks.
#ifdef _WIN32
#include <windows.h>
#endif
namespace mingw_stdthread
{
// Define a portable atomics-based shared_mutex
namespace portable
{
class shared_mutex
{
typedef uint_fast16_t counter_type;
std::atomic< counter_type > mCounter;
static constexpr counter_type kWriteBit = 1
<< (sizeof(counter_type) * CHAR_BIT - 1);
#if STDMUTEX_RECURSION_CHECKS
// Runtime checker for verifying owner threads. Note: Exclusive mode
// only.
_OwnerThread mOwnerThread;
#endif
public:
typedef shared_mutex* native_handle_type;
shared_mutex()
: mCounter(0)
#if STDMUTEX_RECURSION_CHECKS
, mOwnerThread()
#endif
{
}
// No form of copying or moving should be allowed.
shared_mutex(const shared_mutex&) = delete;
shared_mutex&
operator=(const shared_mutex&) = delete;
~shared_mutex()
{
// Terminate if someone tries to destroy an owned mutex.
assert(mCounter.load(std::memory_order_relaxed) == 0);
}
void
lock_shared(void)
{
counter_type expected = mCounter.load(std::memory_order_relaxed);
do
{
// Delay if writing or if too many readers are attempting to read.
if(expected >= kWriteBit - 1)
{
using namespace std;
using namespace this_thread;
yield();
expected = mCounter.load(std::memory_order_relaxed);
continue;
}
if(mCounter.compare_exchange_weak(expected, expected + 1,
std::memory_order_acquire,
std::memory_order_relaxed))
break;
} while(true);
}
bool
try_lock_shared(void)
{
counter_type expected =
mCounter.load(std::memory_order_relaxed) & (~kWriteBit);
if(expected + 1 == kWriteBit)
return false;
else
return mCounter.compare_exchange_strong(expected, expected + 1,
std::memory_order_acquire,
std::memory_order_relaxed);
}
void
unlock_shared(void)
{
using namespace std;
#ifndef NDEBUG
if(!(mCounter.fetch_sub(1, memory_order_release) & (~kWriteBit)))
throw system_error(make_error_code(errc::operation_not_permitted));
#else
mCounter.fetch_sub(1, memory_order_release);
#endif
}
// Behavior is undefined if a lock was previously acquired.
void
lock(void)
{
#if STDMUTEX_RECURSION_CHECKS
DWORD self = mOwnerThread.checkOwnerBeforeLock();
#endif
using namespace std;
// Might be able to use relaxed memory order...
// Wait for the write-lock to be unlocked, then claim the write slot.
counter_type current;
while(
(current = mCounter.fetch_or(kWriteBit, std::memory_order_acquire))
& kWriteBit)
this_thread::yield();
// Wait for readers to finish up.
while(current != kWriteBit)
{
this_thread::yield();
current = mCounter.load(std::memory_order_acquire);
}
#if STDMUTEX_RECURSION_CHECKS
mOwnerThread.setOwnerAfterLock(self);
#endif
}
bool
try_lock(void)
{
#if STDMUTEX_RECURSION_CHECKS
DWORD self = mOwnerThread.checkOwnerBeforeLock();
#endif
counter_type expected = 0;
bool ret = mCounter.compare_exchange_strong(expected, kWriteBit,
std::memory_order_acquire,
std::memory_order_relaxed);
#if STDMUTEX_RECURSION_CHECKS
if(ret)
mOwnerThread.setOwnerAfterLock(self);
#endif
return ret;
}
void
unlock(void)
{
#if STDMUTEX_RECURSION_CHECKS
mOwnerThread.checkSetOwnerBeforeUnlock();
#endif
using namespace std;
#ifndef NDEBUG
if(mCounter.load(memory_order_relaxed) != kWriteBit)
throw system_error(make_error_code(errc::operation_not_permitted));
#endif
mCounter.store(0, memory_order_release);
}
native_handle_type
native_handle(void)
{
return this;
}
};
} // Namespace portable
// The native shared_mutex implementation primarily uses features of Windows
// Vista, but the features used for try_lock and try_lock_shared were not
// introduced until Windows 7. To allow limited use while compiling for Vista,
// I define the class without try_* functions in that case.
// Only fully-featured implementations will be placed into namespace std.
#if defined(_WIN32) && (WINVER >= _WIN32_WINNT_VISTA)
namespace vista
{
class condition_variable_any;
}
namespace windows7
{
// We already #include "mingw.mutex.h". May as well reduce redundancy.
class shared_mutex : windows7::mutex
{
// Allow condition_variable_any (and only condition_variable_any) to
// treat a
// shared_mutex as its base class.
friend class vista::condition_variable_any;
public:
using windows7::mutex::lock;
using windows7::mutex::native_handle;
using windows7::mutex::native_handle_type;
using windows7::mutex::unlock;
void
lock_shared(void)
{
AcquireSRWLockShared(native_handle());
}
void
unlock_shared(void)
{
ReleaseSRWLockShared(native_handle());
}
// TryAcquireSRW functions are a Windows 7 feature.
#if(WINVER >= _WIN32_WINNT_WIN7)
bool
try_lock_shared(void)
{
return TryAcquireSRWLockShared(native_handle()) != 0;
}
using windows7::mutex::try_lock;
#endif
};
} // Namespace windows7
#endif // Compiling for Vista
#if(defined(_WIN32) && (WINVER >= _WIN32_WINNT_WIN7))
using windows7::shared_mutex;
#else
using portable::shared_mutex;
#endif
class shared_timed_mutex : shared_mutex
{
typedef shared_mutex Base;
public:
using Base::lock;
using Base::lock_shared;
using Base::try_lock;
using Base::try_lock_shared;
using Base::unlock;
using Base::unlock_shared;
template < class Clock, class Duration >
bool
try_lock_until(const std::chrono::time_point< Clock, Duration >& cutoff)
{
do
{
if(try_lock())
return true;
} while(std::chrono::steady_clock::now() < cutoff);
return false;
}
template < class Rep, class Period >
bool
try_lock_for(const std::chrono::duration< Rep, Period >& rel_time)
{
return try_lock_until(std::chrono::steady_clock::now() + rel_time);
}
template < class Clock, class Duration >
bool
try_lock_shared_until(
const std::chrono::time_point< Clock, Duration >& cutoff)
{
do
{
if(try_lock_shared())
return true;
} while(std::chrono::steady_clock::now() < cutoff);
return false;
}
template < class Rep, class Period >
bool
try_lock_shared_for(const std::chrono::duration< Rep, Period >& rel_time)
{
return try_lock_shared_until(std::chrono::steady_clock::now() + rel_time);
}
};
#if __cplusplus >= 201402L
using std::shared_lock;
#else
// If not supplied by shared_mutex (eg. because C++14 is not supported), I
// supply the various helper classes that the header should have defined.
template < class Mutex >
class shared_lock
{
Mutex* mMutex;
bool mOwns;
// Reduce code redundancy
void
verify_lockable(void)
{
using namespace std;
if(mMutex == nullptr)
throw system_error(make_error_code(errc::operation_not_permitted));
if(mOwns)
throw system_error(
make_error_code(errc::resource_deadlock_would_occur));
}
public:
typedef Mutex mutex_type;
shared_lock(void) noexcept : mMutex(nullptr), mOwns(false)
{
}
shared_lock(shared_lock< Mutex >&& other) noexcept
: mMutex(other.mutex_), mOwns(other.owns_)
{
other.mMutex = nullptr;
other.mOwns = false;
}
explicit shared_lock(mutex_type& m) : mMutex(&m), mOwns(true)
{
mMutex->lock_shared();
}
shared_lock(mutex_type& m, defer_lock_t) noexcept : mMutex(&m), mOwns(false)
{
}
shared_lock(mutex_type& m, adopt_lock_t) : mMutex(&m), mOwns(true)
{
}
shared_lock(mutex_type& m, try_to_lock_t)
: mMutex(&m), mOwns(m.try_lock_shared())
{
}
template < class Rep, class Period >
shared_lock(mutex_type& m,
const std::chrono::duration< Rep, Period >& timeout_duration)
: mMutex(&m), mOwns(m.try_lock_shared_for(timeout_duration))
{
}
template < class Clock, class Duration >
shared_lock(mutex_type& m,
const std::chrono::time_point< Clock, Duration >& timeout_time)
: mMutex(&m), mOwns(m.try_lock_shared_until(timeout_time))
{
}
shared_lock&
operator=(shared_lock< Mutex >&& other) noexcept
{
if(&other != this)
{
if(mOwns)
mMutex->unlock_shared();
mMutex = other.mMutex;
mOwns = other.mOwns;
other.mMutex = nullptr;
other.mOwns = false;
}
return *this;
}
~shared_lock(void)
{
if(mOwns)
mMutex->unlock_shared();
}
shared_lock(const shared_lock< Mutex >&) = delete;
shared_lock&
operator=(const shared_lock< Mutex >&) = delete;
// Shared locking
void
lock(void)
{
verify_lockable();
mMutex->lock_shared();
mOwns = true;
}
bool
try_lock(void)
{
verify_lockable();
mOwns = mMutex->try_lock_shared();
return mOwns;
}
template < class Clock, class Duration >
bool
try_lock_until(const std::chrono::time_point< Clock, Duration >& cutoff)
{
verify_lockable();
do
{
mOwns = mMutex->try_lock_shared();
if(mOwns)
return mOwns;
} while(std::chrono::steady_clock::now() < cutoff);
return false;
}
template < class Rep, class Period >
bool
try_lock_for(const std::chrono::duration< Rep, Period >& rel_time)
{
return try_lock_until(std::chrono::steady_clock::now() + rel_time);
}
void
unlock(void)
{
using namespace std;
if(!mOwns)
throw system_error(make_error_code(errc::operation_not_permitted));
mMutex->unlock_shared();
mOwns = false;
}
// Modifiers
void
swap(shared_lock< Mutex >& other) noexcept
{
using namespace std;
swap(mMutex, other.mMutex);
swap(mOwns, other.mOwns);
}
mutex_type*
release(void) noexcept
{
mutex_type* ptr = mMutex;
mMutex = nullptr;
mOwns = false;
return ptr;
}
// Observers
mutex_type*
mutex(void) const noexcept
{
return mMutex;
}
bool
owns_lock(void) const noexcept
{
return mOwns;
}
explicit operator bool() const noexcept
{
return owns_lock();
}
};
template < class Mutex >
void
swap(shared_lock< Mutex >& lhs, shared_lock< Mutex >& rhs) noexcept
{
lhs.swap(rhs);
}
#endif // C++11
} // Namespace mingw_stdthread
namespace std
{
// Because of quirks of the compiler, the common "using namespace std;"
// directive would flatten the namespaces and introduce ambiguity where there
// was none. Direct specification (std::), however, would be unaffected.
// Take the safe option, and include only in the presence of MinGW's win32
// implementation.
#if(__cplusplus < 201703L) \
|| (defined(__MINGW32__) && !defined(_GLIBCXX_HAS_GTHREADS))
using mingw_stdthread::shared_mutex;
#endif
#if(__cplusplus < 201402L) \
|| (defined(__MINGW32__) && !defined(_GLIBCXX_HAS_GTHREADS))
using mingw_stdthread::shared_lock;
using mingw_stdthread::shared_timed_mutex;
#elif !defined(MINGW_STDTHREAD_REDUNDANCY_WARNING) // Skip repetition
#define MINGW_STDTHREAD_REDUNDANCY_WARNING
#pragma message \
"This version of MinGW seems to include a win32 port of\
pthreads, and probably already has C++ std threading classes implemented,\
based on pthreads. These classes, found in namespace std, are not overridden\
by the mingw-std-thread library. If you would still like to use this\
implementation (as it is more lightweight), use the classes provided in\
namespace mingw_stdthread."
#endif
} // Namespace std
#endif // MINGW_SHARED_MUTEX_H_

@ -0,0 +1,475 @@
/**
* @file mingw.thread.h
* @brief std::thread implementation for MinGW
* (c) 2013-2016 by Mega Limited, Auckland, New Zealand
* @author Alexander Vassilev
*
* @copyright Simplified (2-clause) BSD License.
* You should have received a copy of the license along with this
* program.
*
* This code 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.
* @note
* This file may become part of the mingw-w64 runtime package. If/when this
* happens, the appropriate license will be added, i.e. this code will become
* dual-licensed, and the current BSD 2-clause license will stay.
*/
#ifndef WIN32STDTHREAD_H
#define WIN32STDTHREAD_H
#if !defined(__cplusplus) || (__cplusplus < 201103L)
#error A C++11 compiler is required!
#endif
// Use the standard classes for std::, if available.
#include <thread>
#include <process.h>
#include <windows.h>
#include <cerrno>
#include <chrono>
#include <functional>
#include <memory>
#include <ostream>
#include <system_error>
#include <type_traits>
#ifndef NDEBUG
#include <cstdio>
#endif
// instead of INVALID_HANDLE_VALUE _beginthreadex returns 0
#define _STD_THREAD_INVALID_HANDLE 0
namespace mingw_stdthread
{
namespace detail
{
// For compatibility, implement std::invoke for C++11 and C++14
#if __cplusplus < 201703L
template < bool PMemFunc, bool PMemData >
struct Invoker
{
template < class F, class... Args >
inline static typename std::result_of< F(Args...) >::type
invoke(F&& f, Args&&... args)
{
return std::forward< F >(f)(std::forward< Args >(args)...);
}
};
template < bool >
struct InvokerHelper;
template <>
struct InvokerHelper< false >
{
template < class T1 >
inline static auto
get(T1&& t1) -> decltype(*std::forward< T1 >(t1))
{
return *std::forward< T1 >(t1);
}
template < class T1 >
inline static auto
get(const std::reference_wrapper< T1 >& t1) -> decltype(t1.get())
{
return t1.get();
}
};
template <>
struct InvokerHelper< true >
{
template < class T1 >
inline static auto
get(T1&& t1) -> decltype(std::forward< T1 >(t1))
{
return std::forward< T1 >(t1);
}
};
template <>
struct Invoker< true, false >
{
template < class T, class F, class T1, class... Args >
inline static auto
invoke(F T::*f, T1&& t1, Args&&... args) -> decltype((
InvokerHelper< std::is_base_of< T, typename std::decay< T1 >::type >::
value >::get(std::forward< T1 >(t1))
.*f)(std::forward< Args >(args)...))
{
return (
InvokerHelper<
std::is_base_of< T, typename std::decay< T1 >::type >::value >::
get(std::forward< T1 >(t1))
.*f)(std::forward< Args >(args)...);
}
};
template <>
struct Invoker< false, true >
{
template < class T, class F, class T1, class... Args >
inline static auto
invoke(F T::*f, T1&& t1, Args&&... args)
-> decltype(InvokerHelper< std::is_base_of<
T, typename std::decay< T1 >::type >::value >::get(t1)
.*f)
{
return InvokerHelper< std::is_base_of<
T, typename std::decay< T1 >::type >::value >::get(t1)
.*f;
}
};
template < class F, class... Args >
struct InvokeResult
{
typedef Invoker< std::is_member_function_pointer<
typename std::remove_reference< F >::type >::value,
std::is_member_object_pointer<
typename std::remove_reference< F >::type >::value
&& (sizeof...(Args) == 1) >
invoker;
inline static auto
invoke(F&& f, Args&&... args)
-> decltype(invoker::invoke(std::forward< F >(f),
std::forward< Args >(args)...))
{
return invoker::invoke(std::forward< F >(f),
std::forward< Args >(args)...);
};
};
template < class F, class... Args >
auto
invoke(F&& f, Args&&... args)
-> decltype(InvokeResult< F, Args... >::invoke(
std::forward< F >(f), std::forward< Args >(args)...))
{
return InvokeResult< F, Args... >::invoke(std::forward< F >(f),
std::forward< Args >(args)...);
}
#else
using std::invoke;
#endif
template < int... >
struct IntSeq
{
};
template < int N, int... S >
struct GenIntSeq : GenIntSeq< N - 1, N - 1, S... >
{
};
template < int... S >
struct GenIntSeq< 0, S... >
{
typedef IntSeq< S... > type;
};
// We can't define the Call struct in the function - the standard forbids
// template methods in that case
template < class Func, typename... Args >
struct ThreadFuncCall
{
typedef std::tuple< Args... > Tuple;
Func mFunc;
Tuple mArgs;
ThreadFuncCall(Func&& aFunc, Args&&... aArgs)
: mFunc(std::forward< Func >(aFunc))
, mArgs(std::forward< Args >(aArgs)...)
{
}
template < int... S >
void
callFunc(detail::IntSeq< S... >)
{
detail::invoke(std::forward< Func >(mFunc),
std::get< S >(std::forward< Tuple >(mArgs))...);
}
};
} // namespace detail
class thread
{
public:
class id
{
DWORD mId;
void
clear()
{
mId = 0;
}
friend class thread;
friend class std::hash< id >;
public:
explicit id(DWORD aId = 0) noexcept : mId(aId)
{
}
friend bool
operator==(id x, id y) noexcept
{
return x.mId == y.mId;
}
friend bool
operator!=(id x, id y) noexcept
{
return x.mId != y.mId;
}
friend bool
operator<(id x, id y) noexcept
{
return x.mId < y.mId;
}
friend bool
operator<=(id x, id y) noexcept
{
return x.mId <= y.mId;
}
friend bool
operator>(id x, id y) noexcept
{
return x.mId > y.mId;
}
friend bool
operator>=(id x, id y) noexcept
{
return x.mId >= y.mId;
}
template < class _CharT, class _Traits >
friend std::basic_ostream< _CharT, _Traits >&
operator<<(std::basic_ostream< _CharT, _Traits >& __out, id __id)
{
if(__id.mId == 0)
{
return __out << "(invalid std::thread::id)";
}
else
{
return __out << __id.mId;
}
}
};
protected:
HANDLE mHandle;
id mThreadId;
public:
typedef HANDLE native_handle_type;
id
get_id() const noexcept
{
return mThreadId;
}
native_handle_type
native_handle() const
{
return mHandle;
}
thread() : mHandle(_STD_THREAD_INVALID_HANDLE), mThreadId()
{
}
thread(thread&& other) : mHandle(other.mHandle), mThreadId(other.mThreadId)
{
other.mHandle = _STD_THREAD_INVALID_HANDLE;
other.mThreadId.clear();
}
thread(const thread& other) = delete;
template < class Func, typename... Args >
explicit thread(Func&& func, Args&&... args) : mHandle(), mThreadId()
{
typedef detail::ThreadFuncCall< Func, Args... > Call;
auto call =
new Call(std::forward< Func >(func), std::forward< Args >(args)...);
mHandle =
(HANDLE)_beginthreadex(NULL, 0, threadfunc< Call, Args... >,
(LPVOID)call, 0, (unsigned*)&(mThreadId.mId));
if(mHandle == _STD_THREAD_INVALID_HANDLE)
{
int errnum = errno;
delete call;
// Note: Should only throw EINVAL, EAGAIN, EACCES
throw std::system_error(errnum, std::generic_category());
}
}
template < class Call, typename... Args >
static unsigned __stdcall threadfunc(void* arg)
{
std::unique_ptr< Call > call(static_cast< Call* >(arg));
call->callFunc(typename detail::GenIntSeq< sizeof...(Args) >::type());
return 0;
}
bool
joinable() const
{
return mHandle != _STD_THREAD_INVALID_HANDLE;
}
void
join()
{
using namespace std;
if(get_id() == id(GetCurrentThreadId()))
throw system_error(
make_error_code(errc::resource_deadlock_would_occur));
if(mHandle == _STD_THREAD_INVALID_HANDLE)
throw system_error(make_error_code(errc::no_such_process));
if(!joinable())
throw system_error(make_error_code(errc::invalid_argument));
WaitForSingleObject(mHandle, INFINITE);
CloseHandle(mHandle);
mHandle = _STD_THREAD_INVALID_HANDLE;
mThreadId.clear();
}
~thread()
{
if(joinable())
{
#ifndef NDEBUG
std::printf(
"Error: Must join() or detach() a thread before \
destroying it.\n");
#endif
std::terminate();
}
}
thread&
operator=(const thread&) = delete;
thread&
operator=(thread&& other) noexcept
{
if(joinable())
{
#ifndef NDEBUG
std::printf(
"Error: Must join() or detach() a thread before \
moving another thread to it.\n");
#endif
std::terminate();
}
swap(std::forward< thread >(other));
return *this;
}
void
swap(thread&& other) noexcept
{
std::swap(mHandle, other.mHandle);
std::swap(mThreadId.mId, other.mThreadId.mId);
}
static unsigned int
_hardware_concurrency_helper() noexcept
{
SYSTEM_INFO sysinfo;
::GetNativeSystemInfo(&sysinfo);
return sysinfo.dwNumberOfProcessors;
}
static unsigned int
hardware_concurrency() noexcept
{
static unsigned int cached = _hardware_concurrency_helper();
return cached;
}
void
detach()
{
if(!joinable())
{
using namespace std;
throw system_error(make_error_code(errc::invalid_argument));
}
if(mHandle != _STD_THREAD_INVALID_HANDLE)
{
CloseHandle(mHandle);
mHandle = _STD_THREAD_INVALID_HANDLE;
}
mThreadId.clear();
}
};
namespace this_thread
{
inline thread::id
get_id() noexcept
{
return thread::id(GetCurrentThreadId());
}
inline void
yield() noexcept
{
Sleep(0);
}
template < class Rep, class Period >
void
sleep_for(const std::chrono::duration< Rep, Period >& sleep_duration)
{
Sleep(std::chrono::duration_cast< std::chrono::milliseconds >(
sleep_duration)
.count());
}
template < class Clock, class Duration >
void
sleep_until(const std::chrono::time_point< Clock, Duration >& sleep_time)
{
sleep_for(sleep_time - Clock::now());
}
} // namespace this_thread
} // Namespace mingw_stdthread
namespace std
{
// Because of quirks of the compiler, the common "using namespace std;"
// directive would flatten the namespaces and introduce ambiguity where there
// was none. Direct specification (std::), however, would be unaffected.
// Take the safe option, and include only in the presence of MinGW's win32
// implementation.
#if defined(__MINGW32__) && !defined(_GLIBCXX_HAS_GTHREADS)
using mingw_stdthread::thread;
// Remove ambiguity immediately, to avoid problems arising from the above.
// using std::thread;
namespace this_thread
{
using namespace mingw_stdthread::this_thread;
}
#elif !defined(MINGW_STDTHREAD_REDUNDANCY_WARNING) // Skip repetition
#define MINGW_STDTHREAD_REDUNDANCY_WARNING
#pragma message \
"This version of MinGW seems to include a win32 port of\
pthreads, and probably already has C++11 std threading classes implemented,\
based on pthreads. These classes, found in namespace std, are not overridden\
by the mingw-std-thread library. If you would still like to use this\
implementation (as it is more lightweight), use the classes provided in\
namespace mingw_stdthread."
#endif
// Specialize hash for this implementation's thread::id, even if the
// std::thread::id already has a hash.
template <>
struct hash< mingw_stdthread::thread::id >
{
typedef mingw_stdthread::thread::id argument_type;
typedef size_t result_type;
size_t
operator()(const argument_type& i) const noexcept
{
return i.mId;
}
};
} // namespace std
#endif // WIN32STDTHREAD_H

File diff suppressed because it is too large Load Diff

@ -23,32 +23,35 @@
* BSDI ifaddrs.h,v 2.5 2000/02/23 14:51:59 dab Exp
*/
#ifndef _IFADDRS_H_
#define _IFADDRS_H_
#ifndef _IFADDRS_H_
#define _IFADDRS_H_
struct ifaddrs {
struct ifaddrs *ifa_next;
char *ifa_name;
unsigned int ifa_flags;
struct sockaddr *ifa_addr;
struct sockaddr *ifa_netmask;
struct sockaddr *ifa_dstaddr;
void *ifa_data;
struct ifaddrs
{
struct ifaddrs *ifa_next;
char *ifa_name;
unsigned int ifa_flags;
struct sockaddr *ifa_addr;
struct sockaddr *ifa_netmask;
struct sockaddr *ifa_dstaddr;
void *ifa_data;
};
/*
* This may have been defined in <net/if.h>. Note that if <net/if.h> is
* to be included it must be included before this header file.
*/
#ifndef ifa_broadaddr
#define ifa_broadaddr ifa_dstaddr /* broadcast address interface */
#ifndef ifa_broadaddr
#define ifa_broadaddr ifa_dstaddr /* broadcast address interface */
#endif
#include <sys/cdefs.h>
__BEGIN_DECLS
extern int getifaddrs(struct ifaddrs **ifap);
extern void freeifaddrs(struct ifaddrs *ifa);
extern int
getifaddrs(struct ifaddrs **ifap);
extern void
freeifaddrs(struct ifaddrs *ifa);
__END_DECLS
#endif

@ -1,12 +1,12 @@
#include "dnsd.hpp" // for llarp_handle_dnsd_recvfrom, dnsc
#include "logger.hpp"
#include <string.h>
#include "dnsd.hpp" // for llarp_handle_dnsd_recvfrom, dnsc
#include "logger.hpp"
uint16_t
get16bits(const char *&buffer) throw()
{
uint16_t value = static_cast< unsigned char >(buffer[0]);
value = value << 8;
value = value << 8;
value += static_cast< unsigned char >(buffer[1]);
buffer += 2;
return value;
@ -29,8 +29,8 @@ decode_hdr(const char *buffer)
dns_msg_header *hdr = new dns_msg_header;
hdr->id = get16bits(buffer);
uint fields = get16bits(buffer);
uint8_t lFields = (fields & 0x00FF) >> 0;
uint8_t hFields = (fields & 0xFF00) >> 8;
uint8_t lFields = (fields & 0x00FF) >> 0;
uint8_t hFields = (fields & 0xFF00) >> 8;
// hdr->qr = fields & 0x8000;
hdr->qr = (hFields >> 7) & 0x1;
hdr->opcode = fields & 0x7800;
@ -38,11 +38,11 @@ decode_hdr(const char *buffer)
hdr->tc = fields & 0x0200;
hdr->rd = fields & 0x0100;
hdr->ra = (lFields >> 7) & 0x1;
//hdr->z = (lFields >> 6) & 0x1;
//hdr->ad = (lFields >> 5) & 0x1;
//hdr->cd = (lFields >> 4) & 0x1;
hdr->rcode = lFields & 0xf;
hdr->ra = (lFields >> 7) & 0x1;
// hdr->z = (lFields >> 6) & 0x1;
// hdr->ad = (lFields >> 5) & 0x1;
// hdr->cd = (lFields >> 4) & 0x1;
hdr->rcode = lFields & 0xf;
hdr->qdCount = get16bits(buffer);
hdr->anCount = get16bits(buffer);
@ -80,17 +80,17 @@ decode_answer(const char *buffer)
{
dns_msg_answer *answer = new dns_msg_answer;
answer->type = get16bits(buffer);
//assert(answer->type < 259);
if (answer->type > 259)
// assert(answer->type < 259);
if(answer->type > 259)
{
llarp::LogWarn("Answer type is off the charts");
}
answer->aClass = get16bits(buffer);
answer->ttl = get32bits(buffer);
answer->rdLen = get16bits(buffer);
if (answer->rdLen == 4)
answer->aClass = get16bits(buffer);
answer->ttl = get32bits(buffer);
answer->rdLen = get16bits(buffer);
if(answer->rdLen == 4)
{
answer->rData = new uint8_t[answer->rdLen];
answer->rData = new uint8_t[answer->rdLen];
memcpy(answer->rData, buffer, answer->rdLen);
}
else

@ -1,24 +1,24 @@
#ifndef LIBLLARP_DNS_HPP
#define LIBLLARP_DNS_HPP
#include <string>
#include <sys/types.h> // for uint & ssize_t
#include <string>
// protocol parsing/writing structures & functions
struct dns_msg_header
{
uint16_t id;
uint8_t qr:1;
uint8_t opcode:4;
uint8_t aa:1;
uint8_t tc:1;
uint8_t rd:1;
uint8_t ra:1;
uint8_t z:1;
uint8_t ad:1;
uint8_t cd:1;
uint8_t rcode:4;
uint8_t qr : 1;
uint8_t opcode : 4;
uint8_t aa : 1;
uint8_t tc : 1;
uint8_t rd : 1;
uint8_t ra : 1;
uint8_t z : 1;
uint8_t ad : 1;
uint8_t cd : 1;
uint8_t rcode : 4;
uint16_t qdCount;
uint16_t anCount;

@ -28,16 +28,16 @@
struct dns_query
{
uint16_t length;
//char *url;
// char *url;
unsigned char request[DNC_BUF_SIZE];
//uint16_t reqType;
// uint16_t reqType;
};
struct dns_query*
struct dns_query *
build_dns_packet(char *url, uint16_t id, uint16_t reqType)
{
dns_query *dnsQuery = new dns_query;
dnsQuery->length = 12;
dnsQuery->length = 12;
// ID
// buffer[0] = (value & 0xFF00) >> 8;
// buffer[1] = value & 0xFF;
@ -80,10 +80,10 @@ build_dns_packet(char *url, uint16_t id, uint16_t reqType)
dnsQuery->request[dnsQuery->length++] = 0x00; // End of the host name
dnsQuery->request[dnsQuery->length++] =
0x00; // 0x0001 - Query is a Type A query (host address)
0x00; // 0x0001 - Query is a Type A query (host address)
dnsQuery->request[dnsQuery->length++] = reqType;
dnsQuery->request[dnsQuery->length++] =
0x00; // 0x0001 - Query is class IN (Internet address)
0x00; // 0x0001 - Query is class IN (Internet address)
dnsQuery->request[dnsQuery->length++] = 0x01;
return dnsQuery;
}
@ -91,8 +91,8 @@ build_dns_packet(char *url, uint16_t id, uint16_t reqType)
struct sockaddr *
raw_resolve_host(const char *url)
{
//char *sUrl = strdup(url);
//struct dns_query dnsQuery;
// char *sUrl = strdup(url);
// struct dns_query dnsQuery;
dns_query *dns_packet = build_dns_packet((char *)url, 0xDB42, 1);
/*
@ -256,8 +256,8 @@ raw_resolve_host(const char *url)
}
/* search for and print IPv4 addresses */
//if(dnsQuery.reqType == 0x01)
if (1)
// if(dnsQuery.reqType == 0x01)
if(1)
{
llarp::LogDebug("DNS server's answer is: (type#=%u):", ATYPE);
// printf("IPv4 address(es) for %s:\n", dnsQuery.url);
@ -271,10 +271,10 @@ raw_resolve_host(const char *url)
buffer[i + 2], buffer[i + 3]);
struct sockaddr *g_addr = new sockaddr;
g_addr->sa_family = AF_INET;
#if ((__APPLE__ && __MACH__) || __FreeBSD__)
g_addr->sa_len = sizeof(in_addr);
#if((__APPLE__ && __MACH__) || __FreeBSD__)
g_addr->sa_len = sizeof(in_addr);
#endif
struct in_addr *addr = &((struct sockaddr_in *)g_addr)->sin_addr;
struct in_addr *addr = &((struct sockaddr_in *)g_addr)->sin_addr;
unsigned char *ip;
// have ip point to s_addr
@ -300,10 +300,10 @@ raw_resolve_host(const char *url)
void
llarp_handle_dnsc_recvfrom(struct llarp_udp_io *udp,
const struct sockaddr *saddr, const void *buf,
ssize_t sz)
const struct sockaddr *saddr, const void *buf,
ssize_t sz)
{
//lock_t lock(m_dnsc_Mutex);
// lock_t lock(m_dnsc_Mutex);
// llarp::LogInfo("got a response, udp user is ", udp->user);
unsigned char *castBuf = (unsigned char *)buf;
@ -313,7 +313,7 @@ llarp_handle_dnsc_recvfrom(struct llarp_udp_io *udp,
llarp::LogDebug("Header got client responses for id: ", hdr->id);
// if we sent this out, then there's an id
struct dns_tracker *tracker = (struct dns_tracker *)udp->user;
struct dns_tracker *tracker = (struct dns_tracker *)udp->user;
struct dnsc_answer_request *request = tracker->client_request[hdr->id];
if(!request)
@ -349,12 +349,12 @@ llarp_handle_dnsc_recvfrom(struct llarp_udp_io *udp,
uint16_t MSGID;
*/
uint8_t rcode;
//int length;
// int length;
//struct dns_query *dnsQuery = &request->query;
// struct dns_query *dnsQuery = &request->query;
//rcode = (buffer[3] & 0x0F);
//llarp::LogInfo("dnsc rcode ", rcode);
// rcode = (buffer[3] & 0x0F);
// llarp::LogInfo("dnsc rcode ", rcode);
dns_msg_header *msg = decode_hdr((const char *)castBuf);
castBuf += 12;
@ -382,12 +382,11 @@ llarp_handle_dnsc_recvfrom(struct llarp_udp_io *udp,
castBuf += answer->name.length() + 4 + 4 + 4 + answer->rdLen;
*/
// FIXME: only handling one atm
dns_msg_question *question = nullptr;
for(uint i = 0; i < hdr->qdCount; i++)
{
question = decode_question((const char*)castBuf);
question = decode_question((const char *)castBuf);
llarp::LogDebug("Read a question");
castBuf += question->name.length() + 8;
}
@ -396,15 +395,15 @@ llarp_handle_dnsc_recvfrom(struct llarp_udp_io *udp,
dns_msg_answer *answer = nullptr;
for(uint i = 0; i < hdr->anCount; i++)
{
answer = decode_answer((const char*)castBuf);
answer = decode_answer((const char *)castBuf);
llarp::LogDebug("Read an answer");
castBuf += answer->name.length() + 4 + 4 + 4 + answer->rdLen;
}
// handle authority records (usually no answers with these, so we'll just stomp)
// usually NS records tho
// handle authority records (usually no answers with these, so we'll just
// stomp) usually NS records tho
for(uint i = 0; i < hdr->nsCount; i++)
{
answer = decode_answer((const char*)castBuf);
answer = decode_answer((const char *)castBuf);
llarp::LogDebug("Read an authority");
castBuf += answer->name.length() + 4 + 4 + 4 + answer->rdLen;
}
@ -474,26 +473,26 @@ llarp_handle_dnsc_recvfrom(struct llarp_udp_io *udp,
int ip = 0;
/* search for and print IPv4 addresses */
//if(dnsQuery->reqType == 0x01)
// if(dnsQuery->reqType == 0x01)
if(request->question.type == 1)
{
//llarp::LogInfo("DNS server's answer is: (type#=", ATYPE, "):");
// llarp::LogInfo("DNS server's answer is: (type#=", ATYPE, "):");
llarp::LogDebug("IPv4 address(es) for ", request->question.name, ":");
if (answer->rdLen == 4)
if(answer->rdLen == 4)
{
request->result.sa_family = AF_INET;
#if ((__APPLE__ && __MACH__) || __FreeBSD__)
request->result.sa_len = sizeof(in_addr);
#if((__APPLE__ && __MACH__) || __FreeBSD__)
request->result.sa_len = sizeof(in_addr);
#endif
struct in_addr *addr =
&((struct sockaddr_in *)&request->result)->sin_addr;
&((struct sockaddr_in *)&request->result)->sin_addr;
unsigned char *ip = (unsigned char *)&(addr->s_addr);
ip[0] = answer->rData[0];
ip[1] = answer->rData[1];
ip[2] = answer->rData[2];
ip[3] = answer->rData[3];
ip[0] = answer->rData[0];
ip[1] = answer->rData[1];
ip[2] = answer->rData[2];
ip[3] = answer->rData[3];
llarp::Addr test(request->result);
llarp::LogDebug(test);
@ -516,19 +515,19 @@ llarp_resolve_host(struct dnsc_context *dnsc, const char *url,
dnsc_answer_hook_func resolved, void *user)
{
dnsc_answer_request *request = new dnsc_answer_request;
request->sock = (void *)&dnsc->udp;
request->user = user;
request->resolved = resolved;
request->found = false;
request->context = dnsc;
request->sock = (void *)&dnsc->udp;
request->user = user;
request->resolved = resolved;
request->found = false;
request->context = dnsc;
char *sUrl = strdup(url);
char *sUrl = strdup(url);
request->question.name = sUrl;
request->question.type = 1;
request->question.qClass = 1;
// register request with udp response tracker
dns_tracker *tracker = (dns_tracker *)dnsc->udp->user;
dns_tracker *tracker = (dns_tracker *)dnsc->udp->user;
/*
uint16_t length = 0;
@ -562,13 +561,15 @@ llarp_resolve_host(struct dnsc_context *dnsc, const char *url,
memcpy(bytes + 12, &request->question, qLen);
*/
uint16_t id = ++tracker->c_requests;
uint16_t id = ++tracker->c_requests;
tracker->client_request[id] = request;
//llarp::LogInfo("Sending request #", tracker->c_requests, " ", length, " bytes");
// llarp::LogInfo("Sending request #", tracker->c_requests, " ", length, "
// bytes");
dns_query *dns_packet = build_dns_packet((char *)url, id, 1);
//ssize_t ret = llarp_ev_udp_sendto(dnsc->udp, dnsc->server, bytes, length);
ssize_t ret = llarp_ev_udp_sendto(dnsc->udp, dnsc->server, dns_packet->request, dns_packet->length);
// ssize_t ret = llarp_ev_udp_sendto(dnsc->udp, dnsc->server, bytes, length);
ssize_t ret = llarp_ev_udp_sendto(dnsc->udp, dnsc->server,
dns_packet->request, dns_packet->length);
delete dns_packet;
if(ret < 0)
{

@ -1,8 +1,8 @@
#ifndef LIBLLARP_DNSC_HPP
#define LIBLLARP_DNSC_HPP
#include <llarp/ev.h> // for sockaadr
#include "dns.hpp" // get protocol structs
#include <llarp/ev.h> // for sockaadr
#include "dns.hpp" // get protocol structs
// internal, non-public functions
// well dnsc init/stop are public...

@ -47,7 +47,7 @@ void
writesend_dnss_response(struct sockaddr *hostRes, const struct sockaddr *from,
dnsd_question_request *request)
{
//lock_t lock(m_dnsd2_Mutex);
// lock_t lock(m_dnsd2_Mutex);
if(!hostRes)
{
llarp::LogWarn("Failed to resolve");
@ -105,7 +105,8 @@ handle_dnsc_result(dnsc_answer_request *client_request)
// llarp::LogInfo("phase2 client ", client_request);
// writesend_dnss_response(struct sockaddr *hostRes, const struct sockaddr
// *from, dnsd_question_request *request)
dnsd_question_request *server_request = (dnsd_question_request *)client_request->user;
dnsd_question_request *server_request =
(dnsd_question_request *)client_request->user;
// llarp::Addr test(*server_request->from);
// llarp::LogInfo("server request sock ", server_request->from, " is ", test);
// llarp::LogInfo("phase2 server ", server_request);
@ -120,7 +121,7 @@ void
handle_recvfrom(const char *buffer, ssize_t nbytes, const struct sockaddr *from,
dnsd_question_request *request)
{
//lock_t lock(m_dnsd_Mutex);
// lock_t lock(m_dnsd_Mutex);
const size_t HDR_OFFSET = 12;
const char *p_buffer = buffer;
@ -149,9 +150,9 @@ handle_recvfrom(const char *buffer, ssize_t nbytes, const struct sockaddr *from,
request->question.type = get16bits(p_buffer);
request->question.qClass = get16bits(p_buffer);
//request->m_qName = m_qName;
//request->m_qType = request->question.type;
//request->m_qClass = request->question.qClass;
// request->m_qName = m_qName;
// request->m_qType = request->question.type;
// request->m_qClass = request->question.qClass;
llarp::LogDebug("qName ", request->question.name);
llarp::LogDebug("qType ", request->question.type);
llarp::LogDebug("qClass ", request->question.qClass);
@ -163,11 +164,11 @@ handle_recvfrom(const char *buffer, ssize_t nbytes, const struct sockaddr *from,
llarp::LogInfo("DNS request from ", test2);
*/
if (request->context->intercept)
if(request->context->intercept)
{
sockaddr *intercept = request->context->intercept(request->question.name);
//if(!forward_dns_request(m_qName))
if (intercept != nullptr)
// if(!forward_dns_request(m_qName))
if(intercept != nullptr)
{
// told that hook will handle overrides
sockaddr *fromCopy = new sockaddr(*from);
@ -205,10 +206,11 @@ handle_recvfrom(const char *buffer, ssize_t nbytes, const struct sockaddr *from,
}
void
llarp_handle_dnsd_recvfrom(struct llarp_udp_io *udp, const struct sockaddr *paddr,
const void *buf, ssize_t sz)
llarp_handle_dnsd_recvfrom(struct llarp_udp_io *udp,
const struct sockaddr *paddr, const void *buf,
ssize_t sz)
{
//lock_t lock(m_dnsd3_Mutex);
// lock_t lock(m_dnsd3_Mutex);
// llarp_link *link = static_cast< llarp_link * >(udp->user);
llarp::LogDebug("llarp Received Bytes ", sz);
dnsd_question_request *llarp_dns_request = new dnsd_question_request;
@ -232,10 +234,10 @@ raw_handle_recvfrom(int *sockfd, const struct sockaddr *saddr, const void *buf,
{
llarp::LogInfo("raw Received Bytes ", sz);
dnsd_question_request *llarp_dns_request = new dnsd_question_request;
llarp_dns_request->from = (struct sockaddr *)saddr;
llarp_dns_request->user = (void *)sockfd;
llarp_dns_request->llarp = false;
llarp_dns_request->hook = &raw_sendto_dns_hook_func;
llarp_dns_request->from = (struct sockaddr *)saddr;
llarp_dns_request->user = (void *)sockfd;
llarp_dns_request->llarp = false;
llarp_dns_request->hook = &raw_sendto_dns_hook_func;
handle_recvfrom((char *)buf, sz, saddr, llarp_dns_request);
}
@ -255,7 +257,7 @@ llarp_dnsd_init(struct dnsd_context *dnsd, struct llarp_ev_loop *netloop,
dns_udp_tracker.dnsd = dnsd;
dnsd->intercept = nullptr;
dnsd->intercept = nullptr;
// configure dns client
if(!llarp_dnsc_init(&dnsd->client, &dnsd->udp, dnsc_hostname, dnsc_port))

@ -1,10 +1,10 @@
#ifndef LIBLLARP_DNSD_HPP
#define LIBLLARP_DNSD_HPP
#include "dns.hpp" // question and dnsc
#include "dnsc.hpp"
#include <llarp/ev.h> // for sockaadr
#include <llarp/ev.h> // for sockaadr
#include <string>
#include "dns.hpp" // question and dnsc
#include "dnsc.hpp"
struct dnsd_context;
@ -25,7 +25,7 @@ struct dnsd_question_request
struct sockaddr *from;
sendto_dns_hook_func hook; // sendto hook tbh
// maybe a reference to dnsd_context incase of multiple
dnsd_context *context; // or you can access it via user (udp)
dnsd_context *context; // or you can access it via user (udp)
};
// we could have passed in the source sockaddr in case you wanted to
@ -58,5 +58,4 @@ llarp_dnsd_init(struct dnsd_context *dnsd, struct llarp_ev_loop *netloop,
bool
llarp_dnsd_stop(struct dnsd_context *dnsd);
#endif

@ -2,10 +2,10 @@
#define LLARP_THREADPOOL_HPP
#include <llarp/threadpool.h>
#include <llarp/threading.hpp>
#include <condition_variable>
#include <deque>
#include <mutex>
#include <thread>
#include <vector>

Loading…
Cancel
Save