Remove Mutex class, replace with std::mutex

Also removes unused Condition class
This commit is contained in:
brainiac
2025-12-28 02:11:13 -08:00
parent 4693b11cb2
commit e12c52a66a
20 changed files with 118 additions and 545 deletions
-4
View File
@@ -7,7 +7,6 @@ set(common_sources
classes.cpp classes.cpp
cli/eqemu_command_handler.cpp cli/eqemu_command_handler.cpp
compression.cpp compression.cpp
condition.cpp
content/world_content_service.cpp content/world_content_service.cpp
crash.cpp crash.cpp
crc16.cpp crc16.cpp
@@ -61,7 +60,6 @@ set(common_sources
memory_mapped_file.cpp memory_mapped_file.cpp
misc.cpp misc.cpp
misc_functions.cpp misc_functions.cpp
mutex.cpp
mysql_request_result.cpp mysql_request_result.cpp
mysql_request_row.cpp mysql_request_row.cpp
mysql_stmt.cpp mysql_stmt.cpp
@@ -548,7 +546,6 @@ set(common_headers
cli/terminal_color.hpp cli/terminal_color.hpp
classes.h classes.h
compression.h compression.h
condition.h
content/world_content_service.h content/world_content_service.h
crash.h crash.h
crc16.h crc16.h
@@ -627,7 +624,6 @@ set(common_headers
memory_mapped_file.h memory_mapped_file.h
misc.h misc.h
misc_functions.h misc_functions.h
mutex.h
mysql_request_result.h mysql_request_result.h
mysql_request_row.h mysql_request_row.h
mysql_stmt.h mysql_stmt.h
-146
View File
@@ -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 <http://www.gnu.org/licenses/>.
*/
#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 <pthread.h>
#include <sys/time.h>
#include <errno.h>
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 << "."<<now.tv_usec << endl;
//cout << "timeout=" << timeout.tv_sec << "."<<timeout.tv_nsec << endl;
retcode=pthread_cond_timedwait(&cond,&mutex,&timeout);
pthread_mutex_unlock(&mutex);
return retcode!=ETIMEDOUT;
}
*/
Condition::~Condition()
{
pthread_mutex_lock(&mutex);
pthread_cond_destroy(&cond);
pthread_mutex_unlock(&mutex);
pthread_mutex_destroy(&mutex);
}
#endif
-51
View File
@@ -1,51 +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 <http://www.gnu.org/licenses/>.
*/
#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();
};
+2 -2
View File
@@ -728,7 +728,7 @@ bool Database::LoadVariables()
return true; return true;
} }
LockMutex lock(&Mvarcache); std::scoped_lock lock(Mvarcache);
for (const auto& e : l) { for (const auto& e : l) {
varcache.last_update = std::time(nullptr); varcache.last_update = std::time(nullptr);
@@ -747,7 +747,7 @@ bool Database::LoadVariables()
bool Database::GetVariable(const std::string& name, std::string& value) bool Database::GetVariable(const std::string& name, std::string& value)
{ {
LockMutex lock(&Mvarcache); std::scoped_lock lock(Mvarcache);
if (name.empty()) { if (name.empty()) {
return false; return false;
+3 -4
View File
@@ -20,13 +20,12 @@
#include "common/dbcore.h" #include "common/dbcore.h"
#include "common/eq_packet_structs.h" #include "common/eq_packet_structs.h"
#include "common/eqemu_logsys.h" #include "common/eqemu_logsys.h"
#include "common/linked_list.h"
#include "common/types.h" #include "common/types.h"
#include <cmath> #include <map>
#include <mutex>
#include <string> #include <string>
#include <vector> #include <vector>
#include <map>
#define AUTHENTICATION_TIMEOUT 60 #define AUTHENTICATION_TIMEOUT 60
#define INVALID_ID 0xFFFFFFFF #define INVALID_ID 0xFFFFFFFF
@@ -265,7 +264,7 @@ public:
uint64_t GetNextTableId(const std::string& table_name); uint64_t GetNextTableId(const std::string& table_name);
private: private:
Mutex Mvarcache; std::mutex Mvarcache;
VarCache_Struct varcache; VarCache_Struct varcache;
/* Groups, utility methods. */ /* Groups, utility methods. */
+23 -40
View File
@@ -33,17 +33,9 @@
#endif #endif
DBcore::DBcore() DBcore::DBcore()
: mysql(mysql_init(nullptr))
, m_mutex(std::make_shared<std::mutex>())
{ {
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() DBcore::~DBcore()
@@ -56,20 +48,17 @@ DBcore::~DBcore()
if (mysqlOwner) { if (mysqlOwner) {
mysql_close(mysql); 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 // Sends the MySQL server a keepalive
void DBcore::ping() 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 // well, if's it's locked, someone's using it. If someone's using it, it doesnt need a keepalive
return; return;
} }
mysql_ping(mysql); mysql_ping(mysql);
m_mutex->unlock(); m_mutex->unlock();
} }
@@ -92,7 +81,7 @@ MySQLRequestResult DBcore::QueryDatabase(const char *query, uint32 querylen, boo
BenchTimer timer; BenchTimer timer;
timer.reset(); timer.reset();
LockMutex lock(m_mutex); std::scoped_lock lock(*m_mutex);
// Reconnect if we are not connected before hand. // Reconnect if we are not connected before hand.
if (pStatus != Connected) { if (pStatus != Connected) {
@@ -217,15 +206,12 @@ bool DBcore::Open(
bool iSSL bool iSSL
) )
{ {
LockMutex lock(m_mutex); std::scoped_lock lock(*m_mutex);
safe_delete_array(pHost);
safe_delete_array(pUser); m_host = iHost;
safe_delete_array(pPassword); m_user = iUser;
safe_delete_array(pDatabase); m_password = iPassword;
pHost = strcpy(new char[strlen(iHost) + 1], iHost); m_database = iDatabase;
pUser = strcpy(new char[strlen(iUser) + 1], iUser);
pPassword = strcpy(new char[strlen(iPassword) + 1], iPassword);
pDatabase = strcpy(new char[strlen(iDatabase) + 1], iDatabase);
pCompress = iCompress; pCompress = iCompress;
pPort = iPort; pPort = iPort;
pSSL = iSSL; pSSL = iSSL;
@@ -237,7 +223,9 @@ bool DBcore::Open(uint32 *errnum, char *errbuf)
if (errbuf) { if (errbuf) {
errbuf[0] = 0; errbuf[0] = 0;
} }
LockMutex lock(m_mutex);
std::scoped_lock lock(*m_mutex);
if (GetStatus() == Connected) { if (GetStatus() == Connected) {
return true; return true;
} }
@@ -245,7 +233,7 @@ bool DBcore::Open(uint32 *errnum, char *errbuf)
mysql_close(mysql); mysql_close(mysql);
mysql_init(mysql); // Initialize structure again mysql_init(mysql); // Initialize structure again
} }
if (!pHost) { if (m_host.empty()) {
return false; 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_ENFORCE, &off);
mysql_options(mysql, MYSQL_OPT_SSL_VERIFY_SERVER_CERT, &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; pStatus = Connected;
std::string connected_origin_host = pHost; SetOriginHost(m_host);
SetOriginHost(connected_origin_host);
return true; return true;
} }
@@ -293,9 +280,9 @@ const std::string &DBcore::GetOriginHost() const
return origin_host; 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) std::string DBcore::Escape(const std::string& s)
@@ -307,12 +294,8 @@ std::string DBcore::Escape(const std::string& s)
return temp.data(); return temp.data();
} }
void DBcore::SetMutex(Mutex *mutex) void DBcore::SetMutex(const std::shared_ptr<std::mutex>& mutex)
{ {
if (m_mutex && m_mutex != mutex) {
safe_delete(m_mutex);
}
DBcore::m_mutex = mutex; DBcore::m_mutex = mutex;
} }
@@ -326,7 +309,7 @@ MySQLRequestResult DBcore::QueryDatabaseMulti(const std::string &query)
BenchTimer timer; BenchTimer timer;
timer.reset(); timer.reset();
LockMutex lock(m_mutex); std::scoped_lock lock(*m_mutex);
// Reconnect if we are not connected before hand. // Reconnect if we are not connected before hand.
if (pStatus != Connected) { if (pStatus != Connected) {
@@ -449,5 +432,5 @@ MySQLRequestResult DBcore::QueryDatabaseMulti(const std::string &query)
mysql::PreparedStmt DBcore::Prepare(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);
} }
+18 -18
View File
@@ -17,7 +17,6 @@
*/ */
#pragma once #pragma once
#include "common/mutex.h"
#include "common/mysql_request_result.h" #include "common/mysql_request_result.h"
#include "common/types.h" #include "common/types.h"
@@ -29,7 +28,8 @@
namespace mysql { class PreparedStmt; } namespace mysql { class PreparedStmt; }
class DBcore { class DBcore
{
public: public:
enum eStatus { enum eStatus {
Closed, Connected, Error Closed, Connected, Error
@@ -48,17 +48,17 @@ public:
uint32 DoEscapeString(char *tobuf, const char *frombuf, uint32 fromlen); uint32 DoEscapeString(char *tobuf, const char *frombuf, uint32 fromlen);
void ping(); void ping();
const std::string &GetOriginHost() const; const std::string& GetOriginHost() const;
void SetOriginHost(const std::string &origin_host); void SetOriginHost(const std::string& origin_host);
bool DoesTableExist(const std::string& table_name); bool DoesTableExist(const std::string& table_name);
void SetMySQL(const DBcore &o) void SetMySQL(const DBcore& o)
{ {
mysql = o.mysql; mysql = o.mysql;
mysqlOwner = false; mysqlOwner = false;
} }
void SetMutex(Mutex *mutex); void SetMutex(const std::shared_ptr<std::mutex>& mutex);
// only safe on connections shared with other threads if results buffered // only safe on connections shared with other threads if results buffered
// unsafe to use off main thread due to internal server logging // unsafe to use off main thread due to internal server logging
@@ -81,22 +81,22 @@ protected:
private: private:
bool Open(uint32 *errnum = nullptr, char *errbuf = nullptr); bool Open(uint32 *errnum = nullptr, char *errbuf = nullptr);
MYSQL* mysql; MYSQL* mysql = nullptr;
bool mysqlOwner; bool mysqlOwner = true;
Mutex *m_mutex; eStatus pStatus = Closed;
eStatus pStatus;
std::mutex m_query_lock{}; std::shared_ptr<std::mutex> m_mutex;
std::mutex m_query_lock;
std::string origin_host; std::string origin_host;
char *pHost; std::string m_host;
char *pUser; std::string m_user;
char *pPassword; std::string m_password;
char *pDatabase; std::string m_database;
bool pCompress; bool pCompress = false;
uint32 pPort; uint32 pPort = 0;
bool pSSL; bool pSSL = false;
// allows multiple queries to be executed within the same query // allows multiple queries to be executed within the same query
// do not use this under normal operation // do not use this under normal operation
-162
View File
@@ -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 <http://www.gnu.org/licenses/>.
*/
#include "mutex.h"
#include <iostream>
#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;
}
-50
View File
@@ -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 <http://www.gnu.org/licenses/>.
*/
#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;
};
+10 -6
View File
@@ -18,7 +18,6 @@
#include "mysql_stmt.h" #include "mysql_stmt.h"
#include "common/eqemu_logsys.h" #include "common/eqemu_logsys.h"
#include "common/mutex.h"
#include "common/timer.h" #include "common/timer.h"
#include <charconv> #include <charconv>
@@ -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 // 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 // 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. // changed to one that throws then exceptions need to be caught here.
LockMutex lock(mutex); std::scoped_lock lock(mutex);
mysql_stmt_close(stmt); mysql_stmt_close(stmt);
} }
PreparedStmt::PreparedStmt(MYSQL& mysql, std::string query, Mutex* mutex, StmtOptions 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_mutex(mutex), m_options(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<unsigned long>(m_query.size())) != 0) if (mysql_stmt_prepare(m_stmt.get(), m_query.c_str(), static_cast<unsigned long>(m_query.size())) != 0)
{ {
ThrowError(fmt::format("Prepare error: {}", GetStmtError())); ThrowError(fmt::format("Prepare error: {}", GetStmtError()));
@@ -186,7 +190,7 @@ void PreparedStmt::CheckArgs(size_t argc)
StmtResult PreparedStmt::DoExecute() StmtResult PreparedStmt::DoExecute()
{ {
BenchTimer timer; 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) if (m_need_bind && mysql_stmt_bind_param(m_stmt.get(), m_params.data()) != 0)
{ {
+6 -3
View File
@@ -17,10 +17,12 @@
*/ */
#pragma once #pragma once
#include "mysql.h" #include "mysql.h"
#include <cassert> #include <cassert>
#include <cstring> #include <cstring>
#include <memory> #include <memory>
#include <mutex>
#include <optional> #include <optional>
#include <span> #include <span>
#include <string_view> #include <string_view>
@@ -183,7 +185,7 @@ public:
int64_t, uint64_t, float, double, bool, std::string_view, std::nullptr_t>; int64_t, uint64_t, float, double, bool, std::string_view, std::nullptr_t>;
PreparedStmt() = delete; 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; } const std::string& GetQuery() const { return m_query; }
StmtOptions GetOptions() const { return m_options; } StmtOptions GetOptions() const { return m_options; }
@@ -219,7 +221,8 @@ private:
struct StmtDeleter struct StmtDeleter
{ {
Mutex* mutex = nullptr; std::mutex& mutex;
void operator()(MYSQL_STMT* stmt) noexcept; void operator()(MYSQL_STMT* stmt) noexcept;
}; };
@@ -232,7 +235,7 @@ private:
std::string m_query; std::string m_query;
StmtOptions m_options = {}; StmtOptions m_options = {};
bool m_need_bind = true; bool m_need_bind = true;
Mutex* m_mutex = nullptr; // connection mutex std::mutex& m_mutex; // connection mutex
}; };
} // namespace mysql } // namespace mysql
+26 -23
View File
@@ -142,10 +142,12 @@ RegularOpcodeManager::~RegularOpcodeManager() {
safe_delete_array(eq_to_emu); 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; NormalMemStrategy s;
s.it = this; s.it = this;
MOpcodes.lock();
loaded = true; loaded = true;
eq_to_emu = new EmuOpcode[MAX_EQ_OPCODE]; 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); memset(emu_to_eq, 0, sizeof(uint16)*_maxEmuOpcode);
bool ret = LoadOpcodesFile(filename, &s, report_errors); bool ret = LoadOpcodesFile(filename, &s, report_errors);
MOpcodes.unlock();
return ret; return ret;
} }
bool RegularOpcodeManager::ReloadOpcodes(const char *filename, bool report_errors) { bool RegularOpcodeManager::ReloadOpcodes(const char* filename, bool report_errors)
if(!loaded) {
return(LoadOpcodes(filename)); if (!loaded)
return LoadOpcodes(filename);
std::scoped_lock lock(MOpcodes);
NormalMemStrategy s; NormalMemStrategy s;
s.it = this; s.it = this;
MOpcodes.lock();
memset(eq_to_emu, 0, sizeof(uint16)*MAX_EQ_OPCODE); memset(eq_to_emu, 0, sizeof(uint16) * MAX_EQ_OPCODE);
return LoadOpcodesFile(filename, &s, report_errors);
bool ret = LoadOpcodesFile(filename, &s, report_errors);
MOpcodes.unlock();
return(ret);
} }
uint16 RegularOpcodeManager::EmuToEQ(const EmuOpcode emu_op) { uint16 RegularOpcodeManager::EmuToEQ(const EmuOpcode emu_op) {
//opcode is checked for validity in GetEQOpcode //opcode is checked for validity in GetEQOpcode
uint16 res; uint16 res;
MOpcodes.lock(); {
res = emu_to_eq[emu_op]; std::scoped_lock lock(MOpcodes);
MOpcodes.unlock(); res = emu_to_eq[emu_op];
}
LogNetcodeDetail("[Opcode Manager] Translate emu [{}] ({:#06x}) eq [{:#06x}]", OpcodeNames[emu_op], emu_op, res); 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); return(res);
} }
EmuOpcode RegularOpcodeManager::EQToEmu(const uint16 eq_op) { EmuOpcode RegularOpcodeManager::EQToEmu(const uint16 eq_op)
{
//opcode is checked for validity in GetEmuOpcode //opcode is checked for validity in GetEmuOpcode
//Disabled since current live EQ uses the entire uint16 bitspace for opcodes //Disabled since current live EQ uses the entire uint16 bitspace for opcodes
// if(eq_op > MAX_EQ_OPCODE) // if(eq_op > MAX_EQ_OPCODE)
// return(OP_Unknown); // return(OP_Unknown);
EmuOpcode res; EmuOpcode res;
MOpcodes.lock(); {
res = eq_to_emu[eq_op]; std::scoped_lock lock(MOpcodes);
MOpcodes.unlock(); res = eq_to_emu[eq_op];
}
#ifdef DEBUG_TRANSLATE #ifdef DEBUG_TRANSLATE
fprintf(stderr, "M Translate EQ 0x%.4x to Emu %s (%d)\n", eq_op, OpcodeNames[res], res); fprintf(stderr, "M Translate EQ 0x%.4x to Emu %s (%d)\n", eq_op, OpcodeNames[res], res);
#endif #endif
+2 -2
View File
@@ -18,10 +18,10 @@
#pragma once #pragma once
#include "common/emu_opcodes.h" #include "common/emu_opcodes.h"
#include "common/mutex.h"
#include "common/types.h" #include "common/types.h"
#include <map> #include <map>
#include <mutex>
//enable the use of shared mem opcodes for world and zone only //enable the use of shared mem opcodes for world and zone only
#ifdef ZONE #ifdef ZONE
@@ -56,7 +56,7 @@ public:
protected: protected:
bool loaded; //true if all opcodes loaded 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 //in a shared manager, this dosent protect others
static bool LoadOpcodesFile(const char *filename, OpcodeSetStrategy *s, bool report_errors); static bool LoadOpcodesFile(const char *filename, OpcodeSetStrategy *s, bool report_errors);
+8 -7
View File
@@ -20,9 +20,12 @@
#include "common/eqemu_config.h" #include "common/eqemu_config.h"
#include "common/repositories/zone_repository.h" #include "common/repositories/zone_repository.h"
#include <chrono>
#include <csignal> #include <csignal>
#include <thread> #include <thread>
using namespace std::chrono_literals;
Database db; Database db;
Database db2; Database db2;
@@ -60,8 +63,6 @@ void WorldserverCLI::TestDatabaseConcurrency(int argc, char **argv, argh::parser
LogInfo("Database test"); LogInfo("Database test");
auto mutex = new Mutex;
auto c = EQEmuConfig::get(); auto c = EQEmuConfig::get();
LogInfo("Connecting to MySQL"); LogInfo("Connecting to MySQL");
if (!db.Connect( if (!db.Connect(
@@ -75,19 +76,19 @@ void WorldserverCLI::TestDatabaseConcurrency(int argc, char **argv, argh::parser
return; return;
} }
db.SetMutex(mutex); std::shared_ptr<std::mutex> sharedMutex = std::make_shared<std::mutex>();
db.SetMutex(sharedMutex);
db2.SetMySQL(db); db2.SetMySQL(db);
db2.SetMutex(mutex); db2.SetMutex(sharedMutex);
std::thread(DatabaseTest).detach(); std::thread(DatabaseTest).detach();
std::thread(DatabaseTest).detach(); std::thread(DatabaseTest).detach();
std::thread(DatabaseTestSecondConnection).detach(); std::thread(DatabaseTestSecondConnection).detach();
while (!stop) { while (!stop) {
std::this_thread::sleep_for(0s);
} }
safe_delete(mutex);
} }
-1
View File
@@ -20,7 +20,6 @@
#include "common/eq_packet_structs.h" #include "common/eq_packet_structs.h"
#include "common/event/timer.h" #include "common/event/timer.h"
#include "common/linked_list.h" #include "common/linked_list.h"
#include "common/mutex.h"
#include "common/net/servertalk_client_connection.h" #include "common/net/servertalk_client_connection.h"
#include "common/net/servertalk_legacy_client_connection.h" #include "common/net/servertalk_legacy_client_connection.h"
#include "common/queue.h" #include "common/queue.h"
-1
View File
@@ -18,7 +18,6 @@
#pragma once #pragma once
#include "common/eq_packet_structs.h" #include "common/eq_packet_structs.h"
#include "common/mutex.h"
#include "common/queue.h" #include "common/queue.h"
#include "common/servertalk.h" #include "common/servertalk.h"
#include "common/timer.h" #include "common/timer.h"
+4 -5
View File
@@ -49,8 +49,6 @@
extern WorldConfig Config; extern WorldConfig Config;
auto mutex = new Mutex;
void WorldBoot::GMSayHookCallBackProcessWorld(uint16 log_category, const char *func, std::string message) void WorldBoot::GMSayHookCallBackProcessWorld(uint16 log_category, const char *func, std::string message)
{ {
// we don't want to loop up with chat messages // we don't want to loop up with chat messages
@@ -180,11 +178,13 @@ bool WorldBoot::LoadDatabaseConnections()
} }
else { else {
content_db.SetMySQL(database); content_db.SetMySQL(database);
// when database and content_db share the same underlying mysql connection // 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 // it needs to be protected by a shared mutex otherwise we produce concurrency issues
// when database actions are occurring in different threads // when database actions are occurring in different threads
database.SetMutex(mutex); std::shared_ptr<std::mutex> sharedMutex = std::make_shared<std::mutex>();
content_db.SetMutex(mutex); database.SetMutex(sharedMutex);
content_db.SetMutex(sharedMutex);
} }
return true; return true;
@@ -634,7 +634,6 @@ void WorldBoot::CheckForPossibleConfigurationIssues()
void WorldBoot::Shutdown() void WorldBoot::Shutdown()
{ {
safe_delete(mutex);
} }
void WorldBoot::SendDiscordMessage(int webhook_id, const std::string &message) void WorldBoot::SendDiscordMessage(int webhook_id, const std::string &message)
+4 -6
View File
@@ -26,7 +26,6 @@
#include "common/guilds.h" #include "common/guilds.h"
#include "common/memory_mapped_file.h" #include "common/memory_mapped_file.h"
#include "common/misc.h" #include "common/misc.h"
#include "common/mutex.h"
#include "common/net/eqstream.h" #include "common/net/eqstream.h"
#include "common/opcodemgr.h" #include "common/opcodemgr.h"
#include "common/patches/patches.h" #include "common/patches/patches.h"
@@ -216,8 +215,6 @@ int main(int argc, char **argv)
} }
} }
auto mutex = new Mutex;
LogInfo("Connecting to MySQL"); LogInfo("Connecting to MySQL");
if (!database.Connect( if (!database.Connect(
Config->DatabaseHost.c_str(), Config->DatabaseHost.c_str(),
@@ -245,11 +242,13 @@ int main(int argc, char **argv)
} }
} else { } else {
content_db.SetMySQL(database); content_db.SetMySQL(database);
// when database and content_db share the same underlying mysql connection // 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 // it needs to be protected by a shared mutex otherwise we produce concurrency issues
// when database actions are occurring in different threads // when database actions are occurring in different threads
database.SetMutex(mutex); std::shared_ptr<std::mutex> sharedMutex = std::make_shared<std::mutex>();
content_db.SetMutex(mutex); database.SetMutex(sharedMutex);
content_db.SetMutex(sharedMutex);
} }
//rules: //rules:
@@ -661,7 +660,6 @@ int main(int argc, char **argv)
LogInfo("Proper zone shutdown complete."); LogInfo("Proper zone shutdown complete.");
EQEmuLogSys::Instance()->CloseFileLogs(); EQEmuLogSys::Instance()->CloseFileLogs();
safe_delete(mutex);
safe_delete(QServ); safe_delete(QServ);
return 0; return 0;
+9 -8
View File
@@ -135,10 +135,11 @@ void PetitionList::AddPetition(Petition* pet) {
} }
//Return Values: 0 = Ok ; -1 = Error deleting petition. //Return Values: 0 = Ok ; -1 = Error deleting petition.
int PetitionList::DeletePetition(uint32 petnumber) { int PetitionList::DeletePetition(uint32 petnumber)
{
LinkedListIterator<Petition*> iterator(list); LinkedListIterator<Petition*> iterator(list);
iterator.Reset(); iterator.Reset();
LockMutex lock(&PList_Mutex); std::scoped_lock lock(PList_Mutex);
while(iterator.MoreElements()) { while(iterator.MoreElements()) {
if (iterator.GetData()->GetID() == petnumber) { if (iterator.GetData()->GetID() == petnumber) {
database.DeletePetitionFromDB(iterator.GetData()); database.DeletePetitionFromDB(iterator.GetData());
@@ -179,18 +180,18 @@ void PetitionList::ClearPetitions() {
return; return;
} }
void PetitionList::ReadDatabase() { void PetitionList::ReadDatabase()
LockMutex lock(&PList_Mutex); {
std::scoped_lock lock(PList_Mutex);
ClearPetitions(); ClearPetitions();
database.RefreshPetitionsFromDB(); database.RefreshPetitionsFromDB();
UpdateGMQueue(); UpdateGMQueue();
return;
} }
void PetitionList::UpdatePetition(Petition* pet) { void PetitionList::UpdatePetition(Petition* pet)
LockMutex lock(&PList_Mutex); {
std::scoped_lock lock(PList_Mutex);
database.UpdatePetitionToDB(pet); database.UpdatePetitionToDB(pet);
return;
} }
void ZoneDatabase::DeletePetitionFromDB(Petition* wpet) { void ZoneDatabase::DeletePetitionFromDB(Petition* wpet) {
+3 -6
View File
@@ -18,12 +18,9 @@
#pragma once #pragma once
#include "common/linked_list.h" #include "common/linked_list.h"
#include "common/misc_functions.h"
#include "common/mutex.h"
#include "common/types.h" #include "common/types.h"
#include "common/zone_store.h"
#include "zone/client.h" #include <mutex>
#include "zone/zonedb.h"
class Client; class Client;
@@ -118,5 +115,5 @@ public:
private: private:
LinkedList<Petition*> list; LinkedList<Petition*> list;
Mutex PList_Mutex; std::mutex PList_Mutex;
}; };