diff --git a/common/CMakeLists.txt b/common/CMakeLists.txt index 3f8b29934..2096afc25 100644 --- a/common/CMakeLists.txt +++ b/common/CMakeLists.txt @@ -7,7 +7,6 @@ set(common_sources classes.cpp cli/eqemu_command_handler.cpp compression.cpp - condition.cpp content/world_content_service.cpp crash.cpp crc16.cpp @@ -61,7 +60,6 @@ set(common_sources memory_mapped_file.cpp misc.cpp misc_functions.cpp - mutex.cpp mysql_request_result.cpp mysql_request_row.cpp mysql_stmt.cpp @@ -548,7 +546,6 @@ set(common_headers cli/terminal_color.hpp classes.h compression.h - condition.h content/world_content_service.h crash.h crc16.h @@ -627,7 +624,6 @@ set(common_headers memory_mapped_file.h misc.h misc_functions.h - mutex.h mysql_request_result.h mysql_request_row.h mysql_stmt.h diff --git a/common/condition.cpp b/common/condition.cpp deleted file mode 100644 index 657bc610d..000000000 --- a/common/condition.cpp +++ /dev/null @@ -1,146 +0,0 @@ -/* EQEmu: EQEmulator - - Copyright (C) 2001-2026 EQEmu Development Team - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU 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 General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ -#include "condition.h" - -#ifdef _WINDOWS - - Condition::Condition() - { - m_events[SignalEvent] = CreateEvent (nullptr, // security - FALSE, // is auto-reset event? - FALSE, // is signaled initially? - nullptr); // name - m_events[BroadcastEvent] = CreateEvent (nullptr, // security - TRUE, // is auto-reset event? - FALSE, // is signaled initially? - nullptr); // name - m_waiters = 0; - InitializeCriticalSection(&CSMutex); - } - - Condition::~Condition() - { - DeleteCriticalSection(&CSMutex); - CloseHandle(m_events[SignalEvent]); - CloseHandle(m_events[BroadcastEvent]); - } - - void Condition::Signal() - { - EnterCriticalSection(&CSMutex); - if(m_waiters > 0) - SetEvent(m_events[SignalEvent]); - LeaveCriticalSection(&CSMutex); - } - - void Condition::SignalAll() - { - EnterCriticalSection(&CSMutex); - if(m_waiters > 0) - SetEvent(m_events[BroadcastEvent]); - LeaveCriticalSection(&CSMutex); - } - - void Condition::Wait() - { - EnterCriticalSection(&CSMutex); - - m_waiters++; - - - LeaveCriticalSection(&CSMutex); - int result = WaitForMultipleObjects (_eventCount, m_events, FALSE, INFINITE); - EnterCriticalSection(&CSMutex); - - m_waiters--; - - //see if we are the last person waiting on the condition, and there was a broadcast - //if so, we need to reset the broadcast event. - if(m_waiters == 0 && result == (WAIT_OBJECT_0+BroadcastEvent)) - ResetEvent(m_events[BroadcastEvent]); - - LeaveCriticalSection(&CSMutex); - } - -#else - #include - #include - #include - - Condition::Condition() - { - pthread_cond_init(&cond,nullptr); - pthread_mutex_init(&mutex,nullptr); - } - - void Condition::Signal() - { - pthread_mutex_lock(&mutex); - pthread_cond_signal(&cond); - pthread_mutex_unlock(&mutex); - } - - void Condition::SignalAll() - { - pthread_mutex_lock(&mutex); - pthread_cond_broadcast(&cond); - pthread_mutex_unlock(&mutex); - } - - void Condition::Wait() - { - pthread_mutex_lock(&mutex); - pthread_cond_wait(&cond,&mutex); - pthread_mutex_unlock(&mutex); - } - - /* - I commented this specifically because I think it might be very - difficult to write a windows counterpart to it, so I would like - to discourage its use until we can confirm that it can be reasonably - implemented on windows. - - bool Condition::TimedWait(unsigned long usec) - { - struct timeval now; - struct timespec timeout; - int retcode=0; - pthread_mutex_lock(&mutex); - gettimeofday(&now,nullptr); - now.tv_usec+=usec; - timeout.tv_sec = now.tv_sec + (now.tv_usec/1000000); - timeout.tv_nsec = (now.tv_usec%1000000) *1000; - //cout << "now=" << now.tv_sec << "."<. -*/ -#pragma once - -#include "common/mutex.h" -#include "common/platform/posix/include_pthreads.h" -#include "common/platform/win/include_windows.h" - -//Sombody, someday needs to figure out how to implement a condition -//system on windows... - - -class Condition { - private: -#ifdef WIN32 - enum { - SignalEvent = 0, - BroadcastEvent, - _eventCount - }; - - HANDLE m_events[_eventCount]; - uint32 m_waiters; - CRITICAL_SECTION CSMutex; -#else - pthread_cond_t cond; - pthread_mutex_t mutex; -#endif - public: - Condition(); - void Signal(); - void SignalAll(); - void Wait(); -// bool TimedWait(unsigned long usec); - ~Condition(); -}; diff --git a/common/database.cpp b/common/database.cpp index 83ed14c90..7376cb0da 100644 --- a/common/database.cpp +++ b/common/database.cpp @@ -728,7 +728,7 @@ bool Database::LoadVariables() return true; } - LockMutex lock(&Mvarcache); + std::scoped_lock lock(Mvarcache); for (const auto& e : l) { varcache.last_update = std::time(nullptr); @@ -747,7 +747,7 @@ bool Database::LoadVariables() bool Database::GetVariable(const std::string& name, std::string& value) { - LockMutex lock(&Mvarcache); + std::scoped_lock lock(Mvarcache); if (name.empty()) { return false; diff --git a/common/database.h b/common/database.h index fdb3154b2..ab5d6c271 100644 --- a/common/database.h +++ b/common/database.h @@ -20,13 +20,12 @@ #include "common/dbcore.h" #include "common/eq_packet_structs.h" #include "common/eqemu_logsys.h" -#include "common/linked_list.h" #include "common/types.h" -#include +#include +#include #include #include -#include #define AUTHENTICATION_TIMEOUT 60 #define INVALID_ID 0xFFFFFFFF @@ -265,7 +264,7 @@ public: uint64_t GetNextTableId(const std::string& table_name); private: - Mutex Mvarcache; + std::mutex Mvarcache; VarCache_Struct varcache; /* Groups, utility methods. */ diff --git a/common/dbcore.cpp b/common/dbcore.cpp index d119ceacb..d9985ce41 100644 --- a/common/dbcore.cpp +++ b/common/dbcore.cpp @@ -33,17 +33,9 @@ #endif DBcore::DBcore() + : mysql(mysql_init(nullptr)) + , m_mutex(std::make_shared()) { - mysql = mysql_init(nullptr); - mysqlOwner = true; - pHost = nullptr; - pUser = nullptr; - pPassword = nullptr; - pDatabase = nullptr; - pCompress = false; - pSSL = false; - pStatus = Closed; - m_mutex = new Mutex; } DBcore::~DBcore() @@ -56,20 +48,17 @@ DBcore::~DBcore() if (mysqlOwner) { mysql_close(mysql); } - - safe_delete_array(pHost); - safe_delete_array(pUser); - safe_delete_array(pPassword); - safe_delete_array(pDatabase); } // Sends the MySQL server a keepalive void DBcore::ping() { - if (!m_mutex->trylock()) { + if (!m_mutex->try_lock()) + { // well, if's it's locked, someone's using it. If someone's using it, it doesnt need a keepalive return; } + mysql_ping(mysql); m_mutex->unlock(); } @@ -92,7 +81,7 @@ MySQLRequestResult DBcore::QueryDatabase(const char *query, uint32 querylen, boo BenchTimer timer; timer.reset(); - LockMutex lock(m_mutex); + std::scoped_lock lock(*m_mutex); // Reconnect if we are not connected before hand. if (pStatus != Connected) { @@ -217,15 +206,12 @@ bool DBcore::Open( bool iSSL ) { - LockMutex lock(m_mutex); - safe_delete_array(pHost); - safe_delete_array(pUser); - safe_delete_array(pPassword); - safe_delete_array(pDatabase); - pHost = strcpy(new char[strlen(iHost) + 1], iHost); - pUser = strcpy(new char[strlen(iUser) + 1], iUser); - pPassword = strcpy(new char[strlen(iPassword) + 1], iPassword); - pDatabase = strcpy(new char[strlen(iDatabase) + 1], iDatabase); + std::scoped_lock lock(*m_mutex); + + m_host = iHost; + m_user = iUser; + m_password = iPassword; + m_database = iDatabase; pCompress = iCompress; pPort = iPort; pSSL = iSSL; @@ -237,7 +223,9 @@ bool DBcore::Open(uint32 *errnum, char *errbuf) if (errbuf) { errbuf[0] = 0; } - LockMutex lock(m_mutex); + + std::scoped_lock lock(*m_mutex); + if (GetStatus() == Connected) { return true; } @@ -245,7 +233,7 @@ bool DBcore::Open(uint32 *errnum, char *errbuf) mysql_close(mysql); mysql_init(mysql); // Initialize structure again } - if (!pHost) { + if (m_host.empty()) { return false; } /* @@ -268,11 +256,10 @@ bool DBcore::Open(uint32 *errnum, char *errbuf) mysql_options(mysql, MYSQL_OPT_SSL_ENFORCE, &off); mysql_options(mysql, MYSQL_OPT_SSL_VERIFY_SERVER_CERT, &off); } - if (mysql_real_connect(mysql, pHost, pUser, pPassword, pDatabase, pPort, 0, flags)) { + if (mysql_real_connect(mysql, m_host.c_str(), m_user.c_str(), m_password.c_str(), m_database.c_str(), pPort, nullptr, flags)) { pStatus = Connected; - std::string connected_origin_host = pHost; - SetOriginHost(connected_origin_host); + SetOriginHost(m_host); return true; } @@ -293,9 +280,9 @@ const std::string &DBcore::GetOriginHost() const return origin_host; } -void DBcore::SetOriginHost(const std::string &origin_host) +void DBcore::SetOriginHost(const std::string& originHost) { - DBcore::origin_host = origin_host; + DBcore::origin_host = originHost; } std::string DBcore::Escape(const std::string& s) @@ -307,12 +294,8 @@ std::string DBcore::Escape(const std::string& s) return temp.data(); } -void DBcore::SetMutex(Mutex *mutex) +void DBcore::SetMutex(const std::shared_ptr& mutex) { - if (m_mutex && m_mutex != mutex) { - safe_delete(m_mutex); - } - DBcore::m_mutex = mutex; } @@ -326,7 +309,7 @@ MySQLRequestResult DBcore::QueryDatabaseMulti(const std::string &query) BenchTimer timer; timer.reset(); - LockMutex lock(m_mutex); + std::scoped_lock lock(*m_mutex); // Reconnect if we are not connected before hand. if (pStatus != Connected) { @@ -449,5 +432,5 @@ MySQLRequestResult DBcore::QueryDatabaseMulti(const std::string &query) mysql::PreparedStmt DBcore::Prepare(std::string query) { - return mysql::PreparedStmt(*mysql, std::move(query), m_mutex); + return mysql::PreparedStmt(*mysql, std::move(query), *m_mutex); } diff --git a/common/dbcore.h b/common/dbcore.h index eef5c1d4b..981957335 100644 --- a/common/dbcore.h +++ b/common/dbcore.h @@ -17,7 +17,6 @@ */ #pragma once -#include "common/mutex.h" #include "common/mysql_request_result.h" #include "common/types.h" @@ -29,7 +28,8 @@ namespace mysql { class PreparedStmt; } -class DBcore { +class DBcore +{ public: enum eStatus { Closed, Connected, Error @@ -48,17 +48,17 @@ public: uint32 DoEscapeString(char *tobuf, const char *frombuf, uint32 fromlen); void ping(); - const std::string &GetOriginHost() const; - void SetOriginHost(const std::string &origin_host); + const std::string& GetOriginHost() const; + void SetOriginHost(const std::string& origin_host); bool DoesTableExist(const std::string& table_name); - void SetMySQL(const DBcore &o) + void SetMySQL(const DBcore& o) { mysql = o.mysql; mysqlOwner = false; } - void SetMutex(Mutex *mutex); + void SetMutex(const std::shared_ptr& mutex); // only safe on connections shared with other threads if results buffered // unsafe to use off main thread due to internal server logging @@ -81,22 +81,22 @@ protected: private: bool Open(uint32 *errnum = nullptr, char *errbuf = nullptr); - MYSQL* mysql; - bool mysqlOwner; - Mutex *m_mutex; - eStatus pStatus; + MYSQL* mysql = nullptr; + bool mysqlOwner = true; + eStatus pStatus = Closed; - std::mutex m_query_lock{}; + std::shared_ptr m_mutex; + std::mutex m_query_lock; std::string origin_host; - char *pHost; - char *pUser; - char *pPassword; - char *pDatabase; - bool pCompress; - uint32 pPort; - bool pSSL; + std::string m_host; + std::string m_user; + std::string m_password; + std::string m_database; + bool pCompress = false; + uint32 pPort = 0; + bool pSSL = false; // allows multiple queries to be executed within the same query // do not use this under normal operation diff --git a/common/mutex.cpp b/common/mutex.cpp deleted file mode 100644 index f8c1db00d..000000000 --- a/common/mutex.cpp +++ /dev/null @@ -1,162 +0,0 @@ -/* EQEmu: EQEmulator - - Copyright (C) 2001-2026 EQEmu Development Team - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU 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 General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ -#include "mutex.h" - -#include - -#define DEBUG_MUTEX_CLASS 0 -#if DEBUG_MUTEX_CLASS >= 1 -#endif - -#ifdef _WINDOWS -bool IsTryLockSupported(); -bool TrylockSupported = IsTryLockSupported(); - -bool IsTryLockSupported() { - OSVERSIONINFOEX osvi; - BOOL bOsVersionInfoEx; - - ZeroMemory(&osvi, sizeof(OSVERSIONINFOEX)); - osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX); - - if( !(bOsVersionInfoEx = GetVersionEx ((OSVERSIONINFO *) &osvi)) ) - { - // If OSVERSIONINFOEX doesn't work, try OSVERSIONINFO. - osvi.dwOSVersionInfoSize = sizeof (OSVERSIONINFO); - if (! GetVersionEx ( (OSVERSIONINFO *) &osvi) ) { -#if DEBUG_MUTEX_CLASS >= 1 - std::cout << "Mutex::trylock() NOT supported" << std::endl; -#endif - return false; - } - } - - // Tests for Windows NT product family. - if (osvi.dwPlatformId == VER_PLATFORM_WIN32_NT && osvi.dwMajorVersion >= 4) { -#if DEBUG_MUTEX_CLASS >= 1 - std::cout << "Mutex::trylock() SUPPORTED" << std::endl; -#endif - return true; - } - else { -#if DEBUG_MUTEX_CLASS >= 1 - std::cout << "Mutex::trylock() NOT supported" << std::endl; -#endif - return false; - } -} -#endif - -Mutex::Mutex() { - -#if DEBUG_MUTEX_CLASS >= 7 - std::cout << "Constructing Mutex" << std::endl; -#endif -#ifdef _WINDOWS - InitializeCriticalSection(&CSMutex); -#else - pthread_mutexattr_t attr; - pthread_mutexattr_init(&attr); -#if defined(__CYGWIN__) || defined(__APPLE__) || defined(FREEBSD) - pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); -#else - pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE_NP); -#endif - pthread_mutex_init(&CSMutex, &attr); - pthread_mutexattr_destroy(&attr); -#endif -} - -Mutex::~Mutex() { -#ifdef _WINDOWS - DeleteCriticalSection(&CSMutex); -#else -#endif -} - -void Mutex::lock() { -#if DEBUG_MUTEX_CLASS >= 5 - if (!trylock()) { - std::cout << "Locking Mutex: Having to wait" << std::endl; - #ifdef _WINDOWS - EnterCriticalSection(&CSMutex); - #else - pthread_mutex_lock(&CSMutex); - #endif - } -#else - #ifdef _WINDOWS - EnterCriticalSection(&CSMutex); - #else - pthread_mutex_lock(&CSMutex); - #endif -#endif -} - -bool Mutex::trylock() { -#ifdef _WINDOWS - #if(_WIN32_WINNT >= 0x0400) - if (TrylockSupported) - return TryEnterCriticalSection(&CSMutex); - else { - EnterCriticalSection(&CSMutex); - return true; - } - #else - EnterCriticalSection(&CSMutex); - return true; - #endif -#else - return (pthread_mutex_trylock(&CSMutex) == 0); -#endif -} - -void Mutex::unlock() { -#ifdef _WINDOWS - LeaveCriticalSection(&CSMutex); -#else - pthread_mutex_unlock(&CSMutex); -#endif -} - - -LockMutex::LockMutex(Mutex* in_mut, bool iLock) { - mut = in_mut; - locked = iLock; - if (locked) { - mut->lock(); - } -} - -LockMutex::~LockMutex() { - if (locked) { - mut->unlock(); - } -} - -void LockMutex::unlock() { - if (locked) - mut->unlock(); - locked = false; -} - -void LockMutex::lock() { - if (!locked) - mut->lock(); - locked = true; -} diff --git a/common/mutex.h b/common/mutex.h deleted file mode 100644 index 8040ec2aa..000000000 --- a/common/mutex.h +++ /dev/null @@ -1,50 +0,0 @@ -/* EQEmu: EQEmulator - - Copyright (C) 2001-2026 EQEmu Development Team - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU 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 General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ -#pragma once - -#include "common/types.h" -#include "common/platform/posix/include_pthreads.h" -#include "common/platform/win/include_windows.h" - -class Mutex { -public: - Mutex(); - ~Mutex(); - - void lock(); - void unlock(); - bool trylock(); -protected: -private: -#if defined _WINDOWS - CRITICAL_SECTION CSMutex; -#else - pthread_mutex_t CSMutex; -#endif -}; - -class LockMutex { -public: - LockMutex(Mutex* in_mut, bool iLock = true); - ~LockMutex(); - void unlock(); - void lock(); -private: - bool locked; - Mutex* mut; -}; diff --git a/common/mysql_stmt.cpp b/common/mysql_stmt.cpp index 8665c16f9..a32133bd9 100644 --- a/common/mysql_stmt.cpp +++ b/common/mysql_stmt.cpp @@ -18,7 +18,6 @@ #include "mysql_stmt.h" #include "common/eqemu_logsys.h" -#include "common/mutex.h" #include "common/timer.h" #include @@ -31,14 +30,19 @@ void PreparedStmt::StmtDeleter::operator()(MYSQL_STMT* stmt) noexcept // The connection must be locked when closing the stmt to avoid mysql errors // in case another thread tries to use it during the close. If the mutex is // changed to one that throws then exceptions need to be caught here. - LockMutex lock(mutex); + std::scoped_lock lock(mutex); + mysql_stmt_close(stmt); } -PreparedStmt::PreparedStmt(MYSQL& mysql, std::string query, Mutex* mutex, StmtOptions opts) - : m_stmt(mysql_stmt_init(&mysql), { mutex }), m_query(std::move(query)), m_mutex(mutex), m_options(opts) +PreparedStmt::PreparedStmt(MYSQL& mysql, std::string query, std::mutex& mutex, StmtOptions opts) + : m_stmt(mysql_stmt_init(&mysql), { mutex }) + , m_query(std::move(query)) + , m_options(opts) + , m_mutex(mutex) { - LockMutex lock(m_mutex); + std::scoped_lock lock(m_mutex); + if (mysql_stmt_prepare(m_stmt.get(), m_query.c_str(), static_cast(m_query.size())) != 0) { ThrowError(fmt::format("Prepare error: {}", GetStmtError())); @@ -186,7 +190,7 @@ void PreparedStmt::CheckArgs(size_t argc) StmtResult PreparedStmt::DoExecute() { BenchTimer timer; - LockMutex lock(m_mutex); + std::scoped_lock lock(m_mutex); if (m_need_bind && mysql_stmt_bind_param(m_stmt.get(), m_params.data()) != 0) { diff --git a/common/mysql_stmt.h b/common/mysql_stmt.h index 63cda89d3..69bd97d41 100644 --- a/common/mysql_stmt.h +++ b/common/mysql_stmt.h @@ -17,10 +17,12 @@ */ #pragma once + #include "mysql.h" #include #include #include +#include #include #include #include @@ -183,7 +185,7 @@ public: int64_t, uint64_t, float, double, bool, std::string_view, std::nullptr_t>; PreparedStmt() = delete; - PreparedStmt(MYSQL& mysql, std::string query, Mutex* mutex, StmtOptions opts = {}); + PreparedStmt(MYSQL& mysql, std::string query, std::mutex& mutex, StmtOptions opts = {}); const std::string& GetQuery() const { return m_query; } StmtOptions GetOptions() const { return m_options; } @@ -219,7 +221,8 @@ private: struct StmtDeleter { - Mutex* mutex = nullptr; + std::mutex& mutex; + void operator()(MYSQL_STMT* stmt) noexcept; }; @@ -232,7 +235,7 @@ private: std::string m_query; StmtOptions m_options = {}; bool m_need_bind = true; - Mutex* m_mutex = nullptr; // connection mutex + std::mutex& m_mutex; // connection mutex }; } // namespace mysql diff --git a/common/opcodemgr.cpp b/common/opcodemgr.cpp index c14888e7c..d028d139b 100644 --- a/common/opcodemgr.cpp +++ b/common/opcodemgr.cpp @@ -142,10 +142,12 @@ RegularOpcodeManager::~RegularOpcodeManager() { safe_delete_array(eq_to_emu); } -bool RegularOpcodeManager::LoadOpcodes(const char *filename, bool report_errors) { +bool RegularOpcodeManager::LoadOpcodes(const char *filename, bool report_errors) +{ + std::scoped_lock lock(MOpcodes); + NormalMemStrategy s; s.it = this; - MOpcodes.lock(); loaded = true; eq_to_emu = new EmuOpcode[MAX_EQ_OPCODE]; @@ -158,32 +160,30 @@ bool RegularOpcodeManager::LoadOpcodes(const char *filename, bool report_errors) memset(emu_to_eq, 0, sizeof(uint16)*_maxEmuOpcode); bool ret = LoadOpcodesFile(filename, &s, report_errors); - MOpcodes.unlock(); return ret; } -bool RegularOpcodeManager::ReloadOpcodes(const char *filename, bool report_errors) { - if(!loaded) - return(LoadOpcodes(filename)); +bool RegularOpcodeManager::ReloadOpcodes(const char* filename, bool report_errors) +{ + if (!loaded) + return LoadOpcodes(filename); + + std::scoped_lock lock(MOpcodes); NormalMemStrategy s; s.it = this; - MOpcodes.lock(); - memset(eq_to_emu, 0, sizeof(uint16)*MAX_EQ_OPCODE); - - bool ret = LoadOpcodesFile(filename, &s, report_errors); - - MOpcodes.unlock(); - return(ret); + memset(eq_to_emu, 0, sizeof(uint16) * MAX_EQ_OPCODE); + return LoadOpcodesFile(filename, &s, report_errors); } uint16 RegularOpcodeManager::EmuToEQ(const EmuOpcode emu_op) { //opcode is checked for validity in GetEQOpcode uint16 res; - MOpcodes.lock(); - res = emu_to_eq[emu_op]; - MOpcodes.unlock(); + { + std::scoped_lock lock(MOpcodes); + res = emu_to_eq[emu_op]; + } LogNetcodeDetail("[Opcode Manager] Translate emu [{}] ({:#06x}) eq [{:#06x}]", OpcodeNames[emu_op], emu_op, res); @@ -193,15 +193,18 @@ uint16 RegularOpcodeManager::EmuToEQ(const EmuOpcode emu_op) { return(res); } -EmuOpcode RegularOpcodeManager::EQToEmu(const uint16 eq_op) { +EmuOpcode RegularOpcodeManager::EQToEmu(const uint16 eq_op) +{ //opcode is checked for validity in GetEmuOpcode -//Disabled since current live EQ uses the entire uint16 bitspace for opcodes -// if(eq_op > MAX_EQ_OPCODE) -// return(OP_Unknown); + //Disabled since current live EQ uses the entire uint16 bitspace for opcodes + // if(eq_op > MAX_EQ_OPCODE) + // return(OP_Unknown); EmuOpcode res; - MOpcodes.lock(); - res = eq_to_emu[eq_op]; - MOpcodes.unlock(); + { + std::scoped_lock lock(MOpcodes); + res = eq_to_emu[eq_op]; + } + #ifdef DEBUG_TRANSLATE fprintf(stderr, "M Translate EQ 0x%.4x to Emu %s (%d)\n", eq_op, OpcodeNames[res], res); #endif diff --git a/common/opcodemgr.h b/common/opcodemgr.h index 152b652aa..d28a02467 100644 --- a/common/opcodemgr.h +++ b/common/opcodemgr.h @@ -18,10 +18,10 @@ #pragma once #include "common/emu_opcodes.h" -#include "common/mutex.h" #include "common/types.h" #include +#include //enable the use of shared mem opcodes for world and zone only #ifdef ZONE @@ -56,7 +56,7 @@ public: protected: bool loaded; //true if all opcodes loaded - Mutex MOpcodes; //this only protects the local machine + std::mutex MOpcodes; //this only protects the local machine //in a shared manager, this dosent protect others static bool LoadOpcodesFile(const char *filename, OpcodeSetStrategy *s, bool report_errors); diff --git a/world/cli/cli_database_concurrency.cpp b/world/cli/cli_database_concurrency.cpp index 557e14174..306407f58 100644 --- a/world/cli/cli_database_concurrency.cpp +++ b/world/cli/cli_database_concurrency.cpp @@ -20,9 +20,12 @@ #include "common/eqemu_config.h" #include "common/repositories/zone_repository.h" +#include #include #include +using namespace std::chrono_literals; + Database db; Database db2; @@ -60,8 +63,6 @@ void WorldserverCLI::TestDatabaseConcurrency(int argc, char **argv, argh::parser LogInfo("Database test"); - auto mutex = new Mutex; - auto c = EQEmuConfig::get(); LogInfo("Connecting to MySQL"); if (!db.Connect( @@ -75,19 +76,19 @@ void WorldserverCLI::TestDatabaseConcurrency(int argc, char **argv, argh::parser return; } - db.SetMutex(mutex); + std::shared_ptr sharedMutex = std::make_shared(); + + db.SetMutex(sharedMutex); db2.SetMySQL(db); - db2.SetMutex(mutex); + db2.SetMutex(sharedMutex); std::thread(DatabaseTest).detach(); std::thread(DatabaseTest).detach(); std::thread(DatabaseTestSecondConnection).detach(); while (!stop) { - + std::this_thread::sleep_for(0s); } - - safe_delete(mutex); } diff --git a/world/login_server.h b/world/login_server.h index b5bd5a038..892917895 100644 --- a/world/login_server.h +++ b/world/login_server.h @@ -20,7 +20,6 @@ #include "common/eq_packet_structs.h" #include "common/event/timer.h" #include "common/linked_list.h" -#include "common/mutex.h" #include "common/net/servertalk_client_connection.h" #include "common/net/servertalk_legacy_client_connection.h" #include "common/queue.h" diff --git a/world/login_server_list.h b/world/login_server_list.h index 7bd3a812a..1911a54ee 100644 --- a/world/login_server_list.h +++ b/world/login_server_list.h @@ -18,7 +18,6 @@ #pragma once #include "common/eq_packet_structs.h" -#include "common/mutex.h" #include "common/queue.h" #include "common/servertalk.h" #include "common/timer.h" diff --git a/world/world_boot.cpp b/world/world_boot.cpp index 7c2afc388..3a07a6632 100644 --- a/world/world_boot.cpp +++ b/world/world_boot.cpp @@ -49,8 +49,6 @@ extern WorldConfig Config; -auto mutex = new Mutex; - void WorldBoot::GMSayHookCallBackProcessWorld(uint16 log_category, const char *func, std::string message) { // we don't want to loop up with chat messages @@ -180,11 +178,13 @@ bool WorldBoot::LoadDatabaseConnections() } else { content_db.SetMySQL(database); + // when database and content_db share the same underlying mysql connection // it needs to be protected by a shared mutex otherwise we produce concurrency issues // when database actions are occurring in different threads - database.SetMutex(mutex); - content_db.SetMutex(mutex); + std::shared_ptr sharedMutex = std::make_shared(); + database.SetMutex(sharedMutex); + content_db.SetMutex(sharedMutex); } return true; @@ -634,7 +634,6 @@ void WorldBoot::CheckForPossibleConfigurationIssues() void WorldBoot::Shutdown() { - safe_delete(mutex); } void WorldBoot::SendDiscordMessage(int webhook_id, const std::string &message) diff --git a/zone/main.cpp b/zone/main.cpp index 82a1c3cf4..6f2c0bdc3 100644 --- a/zone/main.cpp +++ b/zone/main.cpp @@ -26,7 +26,6 @@ #include "common/guilds.h" #include "common/memory_mapped_file.h" #include "common/misc.h" -#include "common/mutex.h" #include "common/net/eqstream.h" #include "common/opcodemgr.h" #include "common/patches/patches.h" @@ -216,8 +215,6 @@ int main(int argc, char **argv) } } - auto mutex = new Mutex; - LogInfo("Connecting to MySQL"); if (!database.Connect( Config->DatabaseHost.c_str(), @@ -245,11 +242,13 @@ int main(int argc, char **argv) } } else { content_db.SetMySQL(database); + // when database and content_db share the same underlying mysql connection // it needs to be protected by a shared mutex otherwise we produce concurrency issues // when database actions are occurring in different threads - database.SetMutex(mutex); - content_db.SetMutex(mutex); + std::shared_ptr sharedMutex = std::make_shared(); + database.SetMutex(sharedMutex); + content_db.SetMutex(sharedMutex); } //rules: @@ -661,7 +660,6 @@ int main(int argc, char **argv) LogInfo("Proper zone shutdown complete."); EQEmuLogSys::Instance()->CloseFileLogs(); - safe_delete(mutex); safe_delete(QServ); return 0; diff --git a/zone/petitions.cpp b/zone/petitions.cpp index cdb946875..4cd2959bd 100644 --- a/zone/petitions.cpp +++ b/zone/petitions.cpp @@ -135,10 +135,11 @@ void PetitionList::AddPetition(Petition* pet) { } //Return Values: 0 = Ok ; -1 = Error deleting petition. -int PetitionList::DeletePetition(uint32 petnumber) { +int PetitionList::DeletePetition(uint32 petnumber) +{ LinkedListIterator iterator(list); iterator.Reset(); - LockMutex lock(&PList_Mutex); + std::scoped_lock lock(PList_Mutex); while(iterator.MoreElements()) { if (iterator.GetData()->GetID() == petnumber) { database.DeletePetitionFromDB(iterator.GetData()); @@ -179,18 +180,18 @@ void PetitionList::ClearPetitions() { return; } -void PetitionList::ReadDatabase() { - LockMutex lock(&PList_Mutex); +void PetitionList::ReadDatabase() +{ + std::scoped_lock lock(PList_Mutex); ClearPetitions(); database.RefreshPetitionsFromDB(); UpdateGMQueue(); - return; } -void PetitionList::UpdatePetition(Petition* pet) { - LockMutex lock(&PList_Mutex); +void PetitionList::UpdatePetition(Petition* pet) +{ + std::scoped_lock lock(PList_Mutex); database.UpdatePetitionToDB(pet); - return; } void ZoneDatabase::DeletePetitionFromDB(Petition* wpet) { diff --git a/zone/petitions.h b/zone/petitions.h index 82afa24ff..82c024eeb 100644 --- a/zone/petitions.h +++ b/zone/petitions.h @@ -18,12 +18,9 @@ #pragma once #include "common/linked_list.h" -#include "common/misc_functions.h" -#include "common/mutex.h" #include "common/types.h" -#include "common/zone_store.h" -#include "zone/client.h" -#include "zone/zonedb.h" + +#include class Client; @@ -118,5 +115,5 @@ public: private: LinkedList list; - Mutex PList_Mutex; + std::mutex PList_Mutex; };