mirror of
https://github.com/mod-playerbots/azerothcore-wotlk.git
synced 2026-01-27 23:56:25 +00:00
feat(Core): replace ACE network with Boost.Asio (#6574)
This commit is contained in:
@@ -28,4 +28,6 @@ void Acore::Banner::Show(char const* applicationName, void(*log)(char const* tex
|
||||
{
|
||||
logExtraInfo();
|
||||
}
|
||||
|
||||
log(" ");
|
||||
}
|
||||
|
||||
@@ -52,7 +52,6 @@ target_link_libraries(common
|
||||
PRIVATE
|
||||
acore-core-interface
|
||||
PUBLIC
|
||||
ace
|
||||
boost
|
||||
argon2
|
||||
g3dlib
|
||||
|
||||
@@ -14,13 +14,12 @@
|
||||
#include <utility>
|
||||
|
||||
#if AC_PLATFORM == AC_PLATFORM_WINDOWS
|
||||
#include <ace/config-all.h>
|
||||
#include <ws2tcpip.h>
|
||||
#if AC_COMPILER == AC_COMPILER_INTEL
|
||||
# if !defined(BOOST_ASIO_HAS_MOVE)
|
||||
# define BOOST_ASIO_HAS_MOVE
|
||||
# endif // !defined(BOOST_ASIO_HAS_MOVE)
|
||||
# endif // if WARHEAD_COMPILER == WARHEAD_COMPILER_INTEL
|
||||
# endif // if AC_COMPILER == AC_COMPILER_INTEL
|
||||
#else
|
||||
#include <cstdlib>
|
||||
#include <netdb.h>
|
||||
|
||||
@@ -16,12 +16,12 @@
|
||||
#define ACORE_BIGENDIAN 1
|
||||
|
||||
#if !defined(ACORE_ENDIAN)
|
||||
# if defined (ACE_BIG_ENDIAN)
|
||||
# if defined (BOOST_BIG_ENDIAN)
|
||||
# define ACORE_ENDIAN ACORE_BIGENDIAN
|
||||
# else //ACE_BYTE_ORDER != ACE_BIG_ENDIAN
|
||||
# else
|
||||
# define ACORE_ENDIAN ACORE_LITTLEENDIAN
|
||||
# endif //ACE_BYTE_ORDER
|
||||
#endif //ACORE_ENDIAN
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if AC_PLATFORM == AC_PLATFORM_WINDOWS
|
||||
# define ACORE_PATH_MAX MAX_PATH
|
||||
|
||||
@@ -12,11 +12,6 @@
|
||||
#include <windows.h>
|
||||
#include <winsvc.h>
|
||||
|
||||
// stupid ACE define
|
||||
#ifdef main
|
||||
#undef main
|
||||
#endif //main
|
||||
|
||||
#if !defined(WINADVAPI)
|
||||
#if !defined(_ADVAPI32_)
|
||||
#define WINADVAPI DECLSPEC_IMPORT
|
||||
|
||||
154
src/common/Threading/MPSCQueue.h
Normal file
154
src/common/Threading/MPSCQueue.h
Normal file
@@ -0,0 +1,154 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license: https://github.com/azerothcore/azerothcore-wotlk/blob/master/LICENSE-AGPL3
|
||||
* Copyright (C) 2021+ WarheadCore <https://github.com/WarheadCore>
|
||||
*/
|
||||
|
||||
#ifndef MPSCQueue_h__
|
||||
#define MPSCQueue_h__
|
||||
|
||||
#include <atomic>
|
||||
#include <utility>
|
||||
|
||||
namespace Acore::Impl
|
||||
{
|
||||
// C++ implementation of Dmitry Vyukov's lock free MPSC queue
|
||||
// http://www.1024cores.net/home/lock-free-algorithms/queues/non-intrusive-mpsc-node-based-queue
|
||||
template<typename T>
|
||||
class MPSCQueueNonIntrusive
|
||||
{
|
||||
public:
|
||||
MPSCQueueNonIntrusive() : _head(new Node()), _tail(_head.load(std::memory_order_relaxed))
|
||||
{
|
||||
Node* front = _head.load(std::memory_order_relaxed);
|
||||
front->Next.store(nullptr, std::memory_order_relaxed);
|
||||
}
|
||||
|
||||
~MPSCQueueNonIntrusive()
|
||||
{
|
||||
T* output;
|
||||
while (Dequeue(output))
|
||||
delete output;
|
||||
|
||||
Node* front = _head.load(std::memory_order_relaxed);
|
||||
delete front;
|
||||
}
|
||||
|
||||
void Enqueue(T* input)
|
||||
{
|
||||
Node* node = new Node(input);
|
||||
Node* prevHead = _head.exchange(node, std::memory_order_acq_rel);
|
||||
prevHead->Next.store(node, std::memory_order_release);
|
||||
}
|
||||
|
||||
bool Dequeue(T*& result)
|
||||
{
|
||||
Node* tail = _tail.load(std::memory_order_relaxed);
|
||||
Node* next = tail->Next.load(std::memory_order_acquire);
|
||||
if (!next)
|
||||
return false;
|
||||
|
||||
result = next->Data;
|
||||
_tail.store(next, std::memory_order_release);
|
||||
delete tail;
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
struct Node
|
||||
{
|
||||
Node() = default;
|
||||
explicit Node(T* data) : Data(data)
|
||||
{
|
||||
Next.store(nullptr, std::memory_order_relaxed);
|
||||
}
|
||||
|
||||
T* Data;
|
||||
std::atomic<Node*> Next;
|
||||
};
|
||||
|
||||
std::atomic<Node*> _head;
|
||||
std::atomic<Node*> _tail;
|
||||
|
||||
MPSCQueueNonIntrusive(MPSCQueueNonIntrusive const&) = delete;
|
||||
MPSCQueueNonIntrusive& operator=(MPSCQueueNonIntrusive const&) = delete;
|
||||
};
|
||||
|
||||
// C++ implementation of Dmitry Vyukov's lock free MPSC queue
|
||||
// http://www.1024cores.net/home/lock-free-algorithms/queues/intrusive-mpsc-node-based-queue
|
||||
template<typename T, std::atomic<T*> T::* IntrusiveLink>
|
||||
class MPSCQueueIntrusive
|
||||
{
|
||||
public:
|
||||
MPSCQueueIntrusive() : _dummyPtr(reinterpret_cast<T*>(std::addressof(_dummy))), _head(_dummyPtr), _tail(_dummyPtr)
|
||||
{
|
||||
// _dummy is constructed from aligned_storage and is intentionally left uninitialized (it might not be default constructible)
|
||||
// so we init only its IntrusiveLink here
|
||||
std::atomic<T*>* dummyNext = new (&(_dummyPtr->*IntrusiveLink)) std::atomic<T*>();
|
||||
dummyNext->store(nullptr, std::memory_order_relaxed);
|
||||
}
|
||||
|
||||
~MPSCQueueIntrusive()
|
||||
{
|
||||
T* output;
|
||||
while (Dequeue(output))
|
||||
delete output;
|
||||
}
|
||||
|
||||
void Enqueue(T* input)
|
||||
{
|
||||
(input->*IntrusiveLink).store(nullptr, std::memory_order_release);
|
||||
T* prevHead = _head.exchange(input, std::memory_order_acq_rel);
|
||||
(prevHead->*IntrusiveLink).store(input, std::memory_order_release);
|
||||
}
|
||||
|
||||
bool Dequeue(T*& result)
|
||||
{
|
||||
T* tail = _tail.load(std::memory_order_relaxed);
|
||||
T* next = (tail->*IntrusiveLink).load(std::memory_order_acquire);
|
||||
if (tail == _dummyPtr)
|
||||
{
|
||||
if (!next)
|
||||
return false;
|
||||
|
||||
_tail.store(next, std::memory_order_release);
|
||||
tail = next;
|
||||
next = (next->*IntrusiveLink).load(std::memory_order_acquire);
|
||||
}
|
||||
|
||||
if (next)
|
||||
{
|
||||
_tail.store(next, std::memory_order_release);
|
||||
result = tail;
|
||||
return true;
|
||||
}
|
||||
|
||||
T* head = _head.load(std::memory_order_acquire);
|
||||
if (tail != head)
|
||||
return false;
|
||||
|
||||
Enqueue(_dummyPtr);
|
||||
next = (tail->*IntrusiveLink).load(std::memory_order_acquire);
|
||||
if (next)
|
||||
{
|
||||
_tail.store(next, std::memory_order_release);
|
||||
result = tail;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private:
|
||||
std::aligned_storage_t<sizeof(T), alignof(T)> _dummy;
|
||||
T* _dummyPtr;
|
||||
std::atomic<T*> _head;
|
||||
std::atomic<T*> _tail;
|
||||
|
||||
MPSCQueueIntrusive(MPSCQueueIntrusive const&) = delete;
|
||||
MPSCQueueIntrusive& operator=(MPSCQueueIntrusive const&) = delete;
|
||||
};
|
||||
}
|
||||
|
||||
template<typename T, std::atomic<T*> T::* IntrusiveLink = nullptr>
|
||||
using MPSCQueue = std::conditional_t<IntrusiveLink != nullptr, Acore::Impl::MPSCQueueIntrusive<T, IntrusiveLink>, Acore::Impl::MPSCQueueNonIntrusive<T>>;
|
||||
|
||||
#endif // MPSCQueue_h__
|
||||
@@ -100,7 +100,7 @@ private:
|
||||
typename std::enable_if<std::is_pointer<E>::value>::type DeleteQueuedObject(E& obj) { delete obj; }
|
||||
|
||||
template<typename E = T>
|
||||
typename std::enable_if < !std::is_pointer<E>::value >::type DeleteQueuedObject(E const& /*packet*/) { }
|
||||
typename std::enable_if<!std::is_pointer<E>::value>::type DeleteQueuedObject(E const& /*packet*/) { }
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,100 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license: https://github.com/azerothcore/azerothcore-wotlk/blob/master/LICENSE-AGPL3
|
||||
* Copyright (C) 2021+ WarheadCore <https://github.com/WarheadCore>
|
||||
*/
|
||||
|
||||
#ifndef _PCQ_H
|
||||
#define _PCQ_H
|
||||
|
||||
#include <condition_variable>
|
||||
#include <mutex>
|
||||
#include <queue>
|
||||
#include <atomic>
|
||||
#include <type_traits>
|
||||
|
||||
template <typename T>
|
||||
class ProducerConsumerQueue
|
||||
{
|
||||
private:
|
||||
std::mutex _queueLock;
|
||||
std::queue<T> _queue;
|
||||
std::condition_variable _condition;
|
||||
std::atomic<bool> _shutdown;
|
||||
|
||||
public:
|
||||
|
||||
ProducerConsumerQueue<T>() : _shutdown(false) { }
|
||||
|
||||
void Push(const T& value)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(_queueLock);
|
||||
_queue.push(std::move(value));
|
||||
|
||||
_condition.notify_one();
|
||||
}
|
||||
|
||||
bool Empty()
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(_queueLock);
|
||||
|
||||
return _queue.empty();
|
||||
}
|
||||
|
||||
bool Pop(T& value)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(_queueLock);
|
||||
|
||||
if (_queue.empty() || _shutdown)
|
||||
return false;
|
||||
|
||||
value = _queue.front();
|
||||
|
||||
_queue.pop();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void WaitAndPop(T& value)
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(_queueLock);
|
||||
|
||||
// we could be using .wait(lock, predicate) overload here but it is broken
|
||||
// https://connect.microsoft.com/VisualStudio/feedback/details/1098841
|
||||
while (_queue.empty() && !_shutdown)
|
||||
_condition.wait(lock);
|
||||
|
||||
if (_queue.empty() || _shutdown)
|
||||
return;
|
||||
|
||||
value = _queue.front();
|
||||
|
||||
_queue.pop();
|
||||
}
|
||||
|
||||
void Cancel()
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(_queueLock);
|
||||
|
||||
while (!_queue.empty())
|
||||
{
|
||||
T& value = _queue.front();
|
||||
|
||||
DeleteQueuedObject(value);
|
||||
|
||||
_queue.pop();
|
||||
}
|
||||
|
||||
_shutdown = true;
|
||||
|
||||
_condition.notify_all();
|
||||
}
|
||||
|
||||
private:
|
||||
template<typename E = T>
|
||||
typename std::enable_if<std::is_pointer<E>::value>::type DeleteQueuedObject(E& obj) { delete obj; }
|
||||
|
||||
template<typename E = T>
|
||||
typename std::enable_if<!std::is_pointer<E>::value>::type DeleteQueuedObject(E const& /*packet*/) { }
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -7,9 +7,9 @@
|
||||
#include "Util.h"
|
||||
#include "Common.h"
|
||||
#include "Containers.h"
|
||||
#include "IpAddress.h"
|
||||
#include "StringConvert.h"
|
||||
#include "StringFormat.h"
|
||||
#include <ace/Default_Constants.h>
|
||||
#include <algorithm>
|
||||
#include <cctype>
|
||||
#include <cstdarg>
|
||||
@@ -17,8 +17,10 @@
|
||||
#include <iomanip>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <cctype>
|
||||
#include <cstdarg>
|
||||
#include <ctime>
|
||||
#include <utf8.h>
|
||||
// #include "IpAddress.h"
|
||||
|
||||
Tokenizer::Tokenizer(const std::string& src, const char sep, uint32 vectorReserve)
|
||||
{
|
||||
@@ -295,26 +297,9 @@ bool IsIPAddress(char const* ipaddress)
|
||||
return false;
|
||||
}
|
||||
|
||||
// Let the big boys do it.
|
||||
// Drawback: all valid ip address formats are recognized e.g.: 12.23, 121234, 0xABCD)
|
||||
return inet_addr(ipaddress) != INADDR_NONE;
|
||||
}
|
||||
|
||||
std::string GetAddressString(ACE_INET_Addr const& addr)
|
||||
{
|
||||
char buf[ACE_MAX_FULLY_QUALIFIED_NAME_LEN + 16];
|
||||
addr.addr_to_string(buf, ACE_MAX_FULLY_QUALIFIED_NAME_LEN + 16);
|
||||
return buf;
|
||||
}
|
||||
|
||||
bool IsIPAddrInNetwork(ACE_INET_Addr const& net, ACE_INET_Addr const& addr, ACE_INET_Addr const& subnetMask)
|
||||
{
|
||||
uint32 mask = subnetMask.get_ip_address();
|
||||
if ((net.get_ip_address() & mask) == (addr.get_ip_address() & mask))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
boost::system::error_code error;
|
||||
Acore::Net::make_address(ipaddress, error);
|
||||
return !error;
|
||||
}
|
||||
|
||||
/// create PID file
|
||||
|
||||
@@ -10,7 +10,6 @@
|
||||
#include "Containers.h"
|
||||
#include "Define.h"
|
||||
#include "Errors.h"
|
||||
#include <ace/INET_Addr.h>
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <cctype>
|
||||
@@ -18,6 +17,9 @@
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <list>
|
||||
#include <map>
|
||||
#include <array>
|
||||
|
||||
// Searcher for map of structs
|
||||
template<typename T, class S> struct Finder
|
||||
@@ -383,12 +385,6 @@ bool Utf8ToUpperOnlyLatin(std::string& utf8String);
|
||||
|
||||
bool IsIPAddress(char const* ipaddress);
|
||||
|
||||
/// Checks if address belongs to the a network with specified submask
|
||||
bool IsIPAddrInNetwork(ACE_INET_Addr const& net, ACE_INET_Addr const& addr, ACE_INET_Addr const& subnetMask);
|
||||
|
||||
/// Transforms ACE_INET_Addr address into string format "dotted_ip:port"
|
||||
std::string GetAddressString(ACE_INET_Addr const& addr);
|
||||
|
||||
uint32 CreatePIDFile(const std::string& filename);
|
||||
uint32 GetPID();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user