Compare commits

...

3 Commits

Author SHA1 Message Date
c3f4cc0e42 clean up mutex 2025-09-06 21:43:05 -05:00
a2183bf2d0 clean up debug 2025-09-06 21:20:01 -05:00
101c1217b2 Clean up common_defines 2025-09-06 21:13:13 -05:00
42 changed files with 1136 additions and 1605 deletions

View File

@ -7,7 +7,7 @@
#ifndef LWORLD_H
#define LWORLD_H
#include "../common/Mutex.h"
#include "../common/mutex.h"
#define ERROR_BADPASSWORD "Bad password"
#define INVALID_ACCOUNT "Invalid Server Account."

View File

@ -21,7 +21,7 @@
#include "../common/types.h"
#include "../common/MiscFunctions.h"
#include "../common/servertalk.h"
#include "../common/Mutex.h"
#include "../common/mutex.h"
#include "PacketHeaders.h"
#include "LoginAccount.h"
#include "LWorld.h"

View File

@ -35,7 +35,7 @@
#include "../common/ConfigReader.h"
#include "../common/Log.h"
#include "../common/JsonParser.h"
#include "../common/Common_Defines.h"
#include "../common/defines.h"
#ifdef WIN32
#define snprintf _snprintf

View File

@ -22,7 +22,7 @@ along with EQ2Emulator. If not, see <http://www.gnu.org/licenses/>.
#define ACHIEVEMENTS_H_
#include "../../common/types.h"
#include "../../common/Mutex.h"
#include "../../common/mutex.h"
#include "../Items/Items.h"
#include <map>
#include <vector>

View File

@ -6,7 +6,7 @@
#include <vector>
#include "../../common/types.h"
#include "../../common/EQPacket.h"
#include "../../common/Mutex.h"
#include "../../common/mutex.h"
#include "../client.h"
#include "ChatChannel.h"

View File

@ -2,7 +2,7 @@
#define COLLECTIONS_H_
#include "../../common/types.h"
#include "../../common/Mutex.h"
#include "../../common/mutex.h"
#include "../Items/Items.h"
#include <map>
#include <vector>

View File

@ -20,7 +20,7 @@
#ifndef __EQ2_ENTITY__
#define __EQ2_ENTITY__
#include "Spawn.h"
#include "../common/Mutex.h"
#include "../common/mutex.h"
#include "Skills.h"
#include "MutexList.h"
#include "MutexVector.h"

View File

@ -4,7 +4,7 @@
#define EQ2_FACTIONS
#include "../common/ConfigReader.h"
#include "../common/Mutex.h"
#include "../common/mutex.h"
struct Faction {
int32 id;
@ -119,4 +119,3 @@ private:
map<int32, int8> faction_percent;
};
#endif

View File

@ -5,7 +5,7 @@
#include "Spawn.h"
#include "client.h"
#include "../common/Mutex.h"
#include "../common/mutex.h"
class GroundSpawn : public Spawn {
public:
@ -66,4 +66,3 @@ private:
bool randomize_heading;
};
#endif

View File

@ -7,7 +7,7 @@
#include <vector>
#include <deque>
#include <map>
#include "../../common/Mutex.h"
#include "../../common/mutex.h"
#include "../MutexMap.h"
using namespace std;

View File

@ -7,7 +7,7 @@
#include "../common/linked_list.h"
#include "../common/timer.h"
#include "../common/queue.h"
#include "../common/Mutex.h"
#include "../common/mutex.h"
#include "../common/TCPConnection.h"
#include <deque>
#include "MutexMap.h"

View File

@ -27,7 +27,7 @@
#include "Spawn.h"
#include "Spells.h"
#include "../common/Mutex.h"
#include "../common/mutex.h"
#include "Quests.h"
#include "zoneserver.h"
#include "client.h"

View File

@ -4,7 +4,7 @@
#define MUTEXHELPER_H
#include "../common/timer.h"
#include "../common/Mutex.h"
#include "../common/mutex.h"
#include <list>
#include <map>

View File

@ -21,7 +21,7 @@
#define RECIPE_H_
#include "../../common/types.h"
#include "../../common/Mutex.h"
#include "../../common/mutex.h"
#include "../classes.h"
#include <string.h>

View File

@ -22,7 +22,7 @@
#include <string.h>
#include <map>
#include "../../common/Mutex.h"
#include "../../common/mutex.h"
#include "../../common/types.h"
using namespace std;

View File

@ -38,7 +38,7 @@
#include "Zone/map.h"
#include "Zone/region_map.h"
#include "Zone/region_map_v1.h"
#include "../common/Mutex.h"
#include "../common/mutex.h"
#include "MutexList.h"
#include <deque>
#include <memory> // needed for LS to compile properly on linux
@ -1594,4 +1594,3 @@ private:
};
#endif

View File

@ -11,7 +11,7 @@
#include "../common/MiscFunctions.h"
#include "client.h"
#include "classes.h"
#include "../common/Mutex.h"
#include "../common/mutex.h"
#include "AltAdvancement/AltAdvancement.h"
#include <lua.hpp>
@ -435,4 +435,3 @@ private:
int32 max_spell_id;
};
#endif

View File

@ -6,7 +6,7 @@
#include <string>
#include <map>
#include <vector>
#include "../common/Mutex.h"
#include "../common/mutex.h"
#include "../common/types.h"
using namespace std;

View File

@ -4,7 +4,7 @@
#define __EQ2_TRADESKILLS__
#include "../../common/types.h"
#include "../../common/Mutex.h"
#include "../../common/mutex.h"
#include "../Items/Items.h"
#include <map>
class Player;

View File

@ -23,7 +23,7 @@ along with EQ2Emulator. If not, see <http://www.gnu.org/licenses/>.
#include <vector>
#include <map>
#include "../../common/Mutex.h"
#include "../../common/mutex.h"
#include "../../common/types.h"
#include "../../common/EQPacket.h"

View File

@ -34,7 +34,7 @@
#include "../common/database.h"
#include "../common/types.h"
#include "../common/MiscFunctions.h"
#include "../common/Mutex.h"
#include "../common/mutex.h"
#include "../common/DatabaseNew.h"
#include "client.h"
#include "Object.h"
@ -686,4 +686,3 @@ private:
std::map<int32, int8> zone_instance_types;
};
#endif

View File

@ -1,7 +1,7 @@
#include <string>
#include <map>
#include <list>
#include "../../common/Mutex.h"
#include "../../common/mutex.h"
#include "../../common/types.h"
#pragma once

View File

@ -24,7 +24,7 @@
#include "../../common/types.h"
#include "../../common/MiscFunctions.h"
#include "../../common/Mutex.h"
#include "../../common/mutex.h"
#include "position.h"
#include <stdio.h>

View File

@ -1,7 +1,7 @@
#pragma once
#include <memory>
#include "../Entity.h"
#include "../../common/Mutex.h"
#include "../../common/mutex.h"
class Mob;
class Client;

View File

@ -44,9 +44,8 @@ using namespace std;
#include "../common/version.h"
#include "../common/EQEMuError.h"
#include "../common/opcodemgr.h"
#include "../common/Common_Defines.h"
#include "../common/defines.h"
#include "../common/JsonParser.h"
#include "../common/Common_Defines.h"
#include "LoginServer.h"
#include "Commands/Commands.h"

View File

@ -30,7 +30,7 @@
#include "../common/servertalk.h"
#include "../common/TCPConnection.h"
#include "WorldTCPConnection.h"
#include "../common/Mutex.h"
#include "../common/mutex.h"
#include "../common/DataBuffer.h"
#include "net.h"
#include "Player.h"

View File

@ -1,15 +0,0 @@
// Copyright (C) 2007-2025 EQ2EMulator
// Licensed under GPL v3
#define BASEDIR "./"
#ifndef DB_INI_FILE
#ifdef LOGIN
#define DB_INI_FILE BASEDIR "login_db.ini"
#else
#define DB_INI_FILE BASEDIR "world_db.ini"
#endif
#endif
#ifndef MAIN_CONFIG_FILE
#define MAIN_CONFIG_FILE BASEDIR "server_config.json"
#endif

View File

@ -8,7 +8,7 @@
#include <string>
#include <vector>
#include "xmlParser.h"
#include "Mutex.h"
#include "mutex.h"
using namespace std;
@ -32,4 +32,3 @@ private:
//vector<PacketStruct*> structs;
};
#endif

View File

@ -6,7 +6,7 @@
#endif
#include "EQEMuError.h"
#include "linked_list.h"
#include "Mutex.h"
#include "mutex.h"
#include "MiscFunctions.h"
#include <stdio.h>
#include <string.h>
@ -110,5 +110,3 @@ void CheckEQEMuErrorAndPause() {
getchar();
}
}

View File

@ -27,7 +27,7 @@
#include "EQStream.h"
#include "EQStreamFactory.h"
#include "misc.h"
#include "Mutex.h"
#include "mutex.h"
#include "op_codes.h"
#include "crypto/crc.h"
#include "packet_dump.h"

View File

@ -18,7 +18,7 @@
// Project headers
#include "EQPacket.h"
#include "Mutex.h"
#include "mutex.h"
#include "opcodemgr.h"
#include "misc.h"
#include "crypto/crypto.h"

View File

@ -1,361 +0,0 @@
/*
EQ2Emulator: Everquest II Server Emulator
Copyright (C) 2007 EQ2EMulator Development Team (http://www.eq2emulator.net)
This file is part of EQ2Emulator.
EQ2Emulator 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.
EQ2Emulator 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 EQ2Emulator. If not, see <http://www.gnu.org/licenses/>.
*/
#include "../common/Log.h"
#include "../common/debug.h"
#include "../common/Mutex.h"
Mutex::Mutex() {
readers = 0;
mlocked = false;
writing = false;
name = "";
#ifdef DEBUG
stack.clear();
#endif
//CSLock is a pointer so we can use a different attribute type on create
CSLock = new CriticalSection(MUTEX_ATTRIBUTE_RECURSIVE);
}
Mutex::~Mutex() {
safe_delete(CSLock);
#ifdef DEBUG
stack.clear();
#endif
}
void Mutex::SetName(string in_name) {
#ifdef DEBUG
name = in_name;
#endif
}
void Mutex::lock() {
#ifdef DEBUG
int i = 0;
#endif
if (name.length() > 0) {
while (mlocked) {
#ifdef DEBUG
if (i > MUTEX_TIMEOUT_MILLISECONDS) {
LogWrite(MUTEX__ERROR, 0, "Mutex", "Possible deadlock attempt by '%s'!", name.c_str());
return;
}
i++;
#endif
Sleep(1);
}
}
mlocked = true;
CSLock->lock();
}
bool Mutex::trylock() {
return CSLock->trylock();
}
void Mutex::unlock() {
CSLock->unlock();
mlocked = false;
}
void Mutex::readlock(const char* function, int32 line) {
#ifdef DEBUG
int32 i = 0;
#endif
while (true) {
//Loop until there isn't a writer, then we can read!
CSRead.lock();
if (!writing) {
readers++;
CSRead.unlock();
#ifdef DEBUG
CSStack.lock();
if (function)
stack[(string)function]++;
CSStack.unlock();
#endif
return;
}
CSRead.unlock();
#ifdef DEBUG
if (i > MUTEX_TIMEOUT_MILLISECONDS) {
LogWrite(MUTEX__ERROR, 0, "Mutex", "The mutex %s called from %s at line %u timed out waiting for a readlock!", name.c_str(), function ? function : "name_not_provided", line);
LogWrite(MUTEX__ERROR, 0, "Mutex", "The following functions had locks:");
map<string, int32>::iterator itr;
CSStack.lock();
for (itr = stack.begin(); itr != stack.end(); itr++) {
if (itr->second > 0 && itr->first.length() > 0)
LogWrite(MUTEX__ERROR, 0, "Mutex", "%s, number of locks = %u", itr->first.c_str(), itr->second);
}
CSStack.unlock();
i = 0;
continue;
}
i++;
#endif
Sleep(1);
}
}
void Mutex::releasereadlock(const char* function, int32 line) {
//Wait for the readcount lock
CSRead.lock();
//Lower the readcount by one, when readcount is 0 writers may start writing
readers--;
CSRead.unlock();
#ifdef DEBUG
CSStack.lock();
if (function) {
map<string, int32>::iterator itr = stack.find((string)function);
if (itr != stack.end()) {
if (--(itr->second) == 0) {
stack.erase(itr);
}
}
}
CSStack.unlock();
#endif
}
bool Mutex::tryreadlock(const char* function) {
//This returns true if able to instantly obtain a readlock, false if not
CSRead.lock();
if (!writing) {
readers++;
CSRead.unlock();
}
else {
CSRead.unlock();
return false;
}
#ifdef DEBUG
CSStack.lock();
if (function)
stack[(string)function]++;
CSStack.unlock();
#endif
return true;
}
void Mutex::writelock(const char* function, int32 line) {
//Wait until the writer lock becomes available, then we can be the only writer!
#ifdef DEBUG
int32 i = 0;
#endif
while (!CSWrite.trylock()) {
#ifdef DEBUG
if (i > MUTEX_TIMEOUT_MILLISECONDS) {
LogWrite(MUTEX__ERROR, 0, "Mutex", "The mutex %s called from %s at line %u timed out waiting on another writelock!", name.c_str(), function ? function : "name_not_provided", line);
LogWrite(MUTEX__ERROR, 0, "Mutex", "The following functions had locks:");
map<string, int32>::iterator itr;
CSStack.lock();
for (itr = stack.begin(); itr != stack.end(); itr++) {
if (itr->second > 0 && itr->first.length() > 0)
LogWrite(MUTEX__ERROR, 0, "Mutex", "%s, number of locks = %u", itr->first.c_str(), itr->second);
}
CSStack.unlock();
i = 0;
continue;
}
i++;
#endif
Sleep(1);
}
waitReaders(function, line);
#ifdef DEBUG
CSStack.lock();
if (function)
stack[(string)function]++;
CSStack.unlock();
#endif
}
void Mutex::releasewritelock(const char* function, int32 line) {
//Wait for the readcount lock
CSRead.lock();
//Readers are aloud again
writing = false;
CSRead.unlock();
//Allow other writers to write
CSWrite.unlock();
#ifdef DEBUG
CSStack.lock();
if (function) {
map<string, int32>::iterator itr = stack.find((string)function);
if (itr != stack.end()) {
if (--(itr->second) == 0) {
stack.erase(itr);
}
}
}
CSStack.unlock();
#endif
}
bool Mutex::trywritelock(const char* function) {
//This returns true if able to instantly obtain a writelock, false if not
if (CSWrite.trylock()) {
CSRead.lock();
if (readers == 0)
writing = true;
CSRead.unlock();
if (!writing) {
CSWrite.unlock();
return false;
}
}
else
return false;
#ifdef DEBUG
CSStack.lock();
if (function)
stack[(string)function]++;
CSStack.unlock();
#endif
return true;
}
void Mutex::waitReaders(const char* function, int32 line)
{
//Wait for all current readers to stop, then we can write!
#ifdef DEBUG
int32 i = 0;
#endif
while (true)
{
CSRead.lock();
if (readers == 0)
{
writing = true;
CSRead.unlock();
break;
}
CSRead.unlock();
#ifdef DEBUG
if (i > MUTEX_TIMEOUT_MILLISECONDS) {
LogWrite(MUTEX__ERROR, 0, "Mutex", "The mutex %s called from %s at line %u timed out while waiting on readers!", name.c_str(), function ? function : "name_not_provided", line);
LogWrite(MUTEX__ERROR, 0, "Mutex", "The following functions had locks:");
map<string, int32>::iterator itr;
CSStack.lock();
for (itr = stack.begin(); itr != stack.end(); itr++) {
if (itr->second > 0 && itr->first.length() > 0)
LogWrite(MUTEX__ERROR, 0, "Mutex", "%s, number of locks = %u", itr->first.c_str(), itr->second);
}
CSStack.unlock();
i = 0;
continue;
}
i++;
#endif
Sleep(1);
}
}
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;
}
CriticalSection::CriticalSection(int attribute) {
#ifdef WIN32
InitializeCriticalSection(&CSMutex);
#else
pthread_mutexattr_init(&type_attribute);
switch (attribute)
{
case MUTEX_ATTRIBUTE_FAST:
pthread_mutexattr_settype(&type_attribute, PTHREAD_MUTEX_FAST_NP);
break;
case MUTEX_ATTRIBUTE_RECURSIVE:
pthread_mutexattr_settype(&type_attribute, PTHREAD_MUTEX_RECURSIVE_NP);
break;
case MUTEX_ATTRIBUTE_ERRORCHK:
pthread_mutexattr_settype(&type_attribute, PTHREAD_MUTEX_ERRORCHECK_NP);
break;
default:
LogWrite(MUTEX__DEBUG, 0, "Critical Section", "Invalid mutex attribute type! Using PTHREAD_MUTEX_FAST_NP");
pthread_mutexattr_settype(&type_attribute, PTHREAD_MUTEX_FAST_NP);
break;
}
pthread_mutex_init(&CSMutex, &type_attribute);
#endif
}
CriticalSection::~CriticalSection() {
#ifdef WIN32
DeleteCriticalSection(&CSMutex);
#else
pthread_mutex_destroy(&CSMutex);
pthread_mutexattr_destroy(&type_attribute);
#endif
}
void CriticalSection::lock() {
//Waits for a lock on this critical section
#ifdef WIN32
EnterCriticalSection(&CSMutex);
#else
pthread_mutex_lock(&CSMutex);
#endif
}
void CriticalSection::unlock() {
//Gets rid of one of the current thread's locks on this critical section
#ifdef WIN32
LeaveCriticalSection(&CSMutex);
#else
pthread_mutex_unlock(&CSMutex);
#endif
}
bool CriticalSection::trylock() {
//Returns true if able to instantly get a lock on this critical section, false if not
#ifdef WIN32
return TryEnterCriticalSection(&CSMutex);
#else
return (pthread_mutex_trylock(&CSMutex) == 0);
#endif
}

View File

@ -1,86 +0,0 @@
// Copyright (C) 2007-2025 EQ2EMulator
// Licensed under GPL v3
#ifndef MYMUTEX_H
#define MYMUTEX_H
#ifdef WIN32
#include <WinSock2.h>
#include <windows.h>
#else
#include <pthread.h>
#include "../common/unix.h"
#endif
#include "../common/types.h"
#include <string>
#include <map>
#define MUTEX_ATTRIBUTE_FAST 1
#define MUTEX_ATTRIBUTE_RECURSIVE 2
#define MUTEX_ATTRIBUTE_ERRORCHK 3
#define MUTEX_TIMEOUT_MILLISECONDS 10000
class CriticalSection {
public:
CriticalSection(int attribute = MUTEX_ATTRIBUTE_FAST);
~CriticalSection();
void lock();
void unlock();
bool trylock();
private:
#ifdef WIN32
CRITICAL_SECTION CSMutex;
#else
pthread_mutex_t CSMutex;
pthread_mutexattr_t type_attribute;
#endif
};
class Mutex {
public:
Mutex();
~Mutex();
void lock();
void unlock();
bool trylock();
void readlock(const char* function = 0, int32 line = 0);
void releasereadlock(const char* function = 0, int32 line = 0);
bool tryreadlock(const char* function = 0);
void writelock(const char* function = 0, int32 line = 0);
void releasewritelock(const char* function = 0, int32 line = 0);
bool trywritelock(const char* function = 0);
void waitReaders(const char* function = 0, int32 line = 0);
void SetName(string in_name);
private:
CriticalSection CSRead;
CriticalSection CSWrite;
CriticalSection* CSLock;
#ifdef DEBUG //Used for debugging only
CriticalSection CSStack;
map<string, int32> stack;
#endif
int readers;
bool writing;
volatile bool mlocked;
string name;
};
class LockMutex {
public:
LockMutex(Mutex* in_mut, bool iLock = true);
~LockMutex();
void unlock();
void lock();
private:
bool locked;
Mutex* mut;
};
#endif

View File

@ -30,7 +30,7 @@
#endif
#include "types.h"
#include "Mutex.h"
#include "mutex.h"
#include "linked_list.h"
#include "queue.h"
#include "servertalk.h"

View File

@ -14,7 +14,7 @@
#include "linked_list.h"
#include "EQStream.h"
#include "MiscFunctions.h"
#include "Mutex.h"
#include "mutex.h"
#include <string>
#include <vector>
#include <map>

View File

@ -10,7 +10,7 @@
#endif
#include <mysql.h>
#include "../common/types.h"
#include "../common/Mutex.h"
#include "../common/mutex.h"
#include "../common/linked_list.h"
#include "../common/queue.h"
#include "../common/timer.h"
@ -58,5 +58,3 @@ private:
bool pSSL;
};
#endif

View File

@ -1,319 +0,0 @@
// Copyright (C) 2007-2025 EQ2EMulator
// Licensed under GPL v3
/*
JA: File rendered obsolete (2011-08-12)
#include "debug.h"
#include <iostream>
using namespace std;
#include <time.h>
#include <string.h>
#ifdef WIN32
#include <process.h>
#define snprintf _snprintf
#define vsnprintf _vsnprintf
#define strncasecmp _strnicmp
#define strcasecmp _stricmp
#else
#include <sys/types.h>
#include <unistd.h>
#include <stdarg.h>
#endif
#include "../common/MiscFunctions.h"
EQEMuLog* LogFile = new EQEMuLog;
AutoDelete<EQEMuLog> adlf(&LogFile);
static const char* FileNames[EQEMuLog::MaxLogID] = { "logs/eq2emu", "logs/eq2emu", "logs/eq2emu_error", "logs/eq2emu_debug", "logs/eq2emu_quest", "logs/eq2emu_commands" };
static const char* LogNames[EQEMuLog::MaxLogID] = { "Status", "Normal", "Error", "Debug", "Quest", "Command" };
EQEMuLog::EQEMuLog() {
for (int i=0; i<MaxLogID; i++) {
fp[i] = 0;
#if EQDEBUG >= 2
pLogStatus[i] = 1 | 2;
#else
pLogStatus[i] = 0;
#endif
logCallbackFmt[i] = NULL;
logCallbackBuf[i] = NULL;
}
#if EQDEBUG < 2
pLogStatus[Status] = 3;
pLogStatus[Error] = 3;
pLogStatus[Debug] = 3;
pLogStatus[Quest] = 2;
pLogStatus[Commands] = 2;
#endif
}
EQEMuLog::~EQEMuLog() {
for (int i=0; i<MaxLogID; i++) {
if (fp[i])
fclose(fp[i]);
}
}
bool EQEMuLog::open(LogIDs id) {
if (id >= MaxLogID) {
return false;
}
LockMutex lock(&MOpen);
if (pLogStatus[id] & 4) {
return false;
}
if (fp[id]) {
return true;
}
char exename[200] = "";
#if defined(WORLD)
snprintf(exename, sizeof(exename), "_world");
#elif defined(ZONE)
snprintf(exename, sizeof(exename), "_zone");
#endif
char filename[200];
#ifndef NO_PIDLOG
snprintf(filename, sizeof(filename), "%s%s_%04i.log", FileNames[id], exename, getpid());
#else
snprintf(filename, sizeof(filename), "%s%s.log", FileNames[id], exename);
#endif
fp[id] = fopen(filename, "a");
if (!fp[id]) {
cerr << "Failed to open log file: " << filename << endl;
pLogStatus[id] |= 4; // set file state to error
return false;
}
fputs("---------------------------------------------\n",fp[id]);
return true;
}
bool EQEMuLog::write(LogIDs id, const char *fmt, ...) {
char buffer[4096];
if (!this) {
return false;
}
if (id >= MaxLogID) {
return false;
}
bool dofile = false;
if (pLogStatus[id] & 1) {
dofile = open(id);
}
if (!(dofile || pLogStatus[id] & 2))
return false;
LockMutex lock(&MLog[id]);
time_t aclock;
struct tm *newtime;
time( &aclock ); //Get time in seconds
newtime = localtime( &aclock ); //Convert time to struct
if (dofile){
#ifndef NO_PIDLOG
fprintf(fp[id], "[%04d%02d%02d %02d:%02d:%02d] ", newtime->tm_year+1900, newtime->tm_mon+1, newtime->tm_mday, newtime->tm_hour, newtime->tm_min, newtime->tm_sec);
#else
fprintf(fp[id], "%04i [%04d%02d%02d %02d:%02d:%02d] ", getpid(), newtime->tm_year+1900, newtime->tm_mon+1, newtime->tm_mday, newtime->tm_hour, newtime->tm_min, newtime->tm_sec);
#endif
}
va_list argptr;
va_start(argptr, fmt);
vsnprintf(buffer, sizeof(buffer), fmt, argptr);
va_end(argptr);
if (dofile)
fprintf(fp[id], "%s\n", buffer);
if(logCallbackFmt[id]) {
msgCallbackFmt p = logCallbackFmt[id];
p(id, fmt, argptr );
}
if (pLogStatus[id] & 2) {
if (pLogStatus[id] & 8) {
fprintf(stderr, "[%04d%02d%02d %02d:%02d:%02d] [%s] ", newtime->tm_year+1900, newtime->tm_mon+1, newtime->tm_mday, newtime->tm_hour, newtime->tm_min, newtime->tm_sec, LogNames[id]);
fprintf(stderr, "%s\n", buffer);
}
else {
fprintf(stdout, "[%04d%02d%02d %02d:%02d:%02d] [%s] ", newtime->tm_year+1900, newtime->tm_mon+1, newtime->tm_mday, newtime->tm_hour, newtime->tm_min, newtime->tm_sec, LogNames[id]);
fprintf(stdout, "%s\n", buffer);
}
}
if (dofile)
fprintf(fp[id], "\n");
if (pLogStatus[id] & 2) {
if (pLogStatus[id] & 8)
fprintf(stderr, "\n");
else
fprintf(stdout, "\n");
}
if(dofile)
fflush(fp[id]);
return true;
}
bool EQEMuLog::writebuf(LogIDs id, const char *buf, int8 size, int32 count) {
if (!this) {
return false;
}
if (id >= MaxLogID) {
return false;
}
bool dofile = false;
if (pLogStatus[id] & 1) {
dofile = open(id);
}
if (!(dofile || pLogStatus[id] & 2))
return false;
LockMutex lock(&MLog[id]);
time_t aclock;
struct tm *newtime;
time( &aclock ); // Get time in seconds
newtime = localtime( &aclock ); // Convert time to struct
if (dofile){
#ifndef NO_PIDLOG
fprintf(fp[id], "[%02d.%02d. - %02d:%02d:%02d] ", newtime->tm_mon+1, newtime->tm_mday, newtime->tm_hour, newtime->tm_min, newtime->tm_sec);
#else
fprintf(fp[id], "%04i [%02d.%02d. - %02d:%02d:%02d] ", getpid(), newtime->tm_mon+1, newtime->tm_mday, newtime->tm_hour, newtime->tm_min, newtime->tm_sec);
#endif
}
if (dofile) {
fwrite(buf, size, count, fp[id]);
fprintf(fp[id], "\n");
}
if(logCallbackBuf[id]) {
msgCallbackBuf p = logCallbackBuf[id];
p(id, buf, size, count);
}
if (pLogStatus[id] & 2) {
if (pLogStatus[id] & 8) {
fprintf(stderr, "[%s] ", LogNames[id]);
fwrite(buf, size, count, stderr);
fprintf(stderr, "\n");
} else {
fprintf(stdout, "[%s] ", LogNames[id]);
fwrite(buf, size, count, stdout);
fprintf(stdout, "\n");
}
}
if(dofile)
fflush(fp[id]);
return true;
}
bool EQEMuLog::writeNTS(LogIDs id, bool dofile, const char *fmt, ...) {
char buffer[4096];
va_list argptr;
va_start(argptr, fmt);
vsnprintf(buffer, sizeof(buffer), fmt, argptr);
va_end(argptr);
if (dofile)
fprintf(fp[id], "%s\n", buffer);
if (pLogStatus[id] & 2) {
if (pLogStatus[id] & 8)
fprintf(stderr, "%s\n", buffer);
else
fprintf(stdout, "%s\n", buffer);
}
return true;
};
bool EQEMuLog::Dump(LogIDs id, int8* data, int32 size, int32 cols, int32 skip) {
if (!this) {
#if EQDEBUG >= 10
cerr << "Error: Dump() from null pointer"<<endl;
#endif
return false;
}
if (size == 0)
return true;
if (!LogFile)
return false;
if (id >= MaxLogID)
return false;
bool dofile = false;
if (pLogStatus[id] & 1) {
dofile = open(id);
}
if (!(dofile || pLogStatus[id] & 2))
return false;
LockMutex lock(&MLog[id]);
write(id, "Dumping Packet: %i", size);
// Output as HEX
int j = 0; char* ascii = new char[cols+1]; memset(ascii, 0, cols+1);
int32 i;
for(i=skip; i<size; i++) {
if ((i-skip)%cols==0) {
if (i != skip)
writeNTS(id, dofile, " | %s\n", ascii);
writeNTS(id, dofile, "%4i: ", i-skip);
memset(ascii, 0, cols+1);
j = 0;
}
else if ((i-skip)%(cols/2) == 0) {
writeNTS(id, dofile, "- ");
}
writeNTS(id, dofile, "%02X ", (unsigned char)data[i]);
if (data[i] >= 32 && data[i] < 127)
ascii[j++] = data[i];
else
ascii[j++] = '.';
}
int32 k = ((i-skip)-1)%cols;
if (k < 8)
writeNTS(id, dofile, " ");
for (int32 h = k+1; h < cols; h++) {
writeNTS(id, dofile, " ");
}
writeNTS(id, dofile, " | %s\n", ascii);
if (dofile)
fflush(fp[id]);
safe_delete_array(ascii);
return true;
}
void EQEMuLog::SetCallback(LogIDs id, msgCallbackFmt proc) {
if (!this)
return;
if (id >= MaxLogID) {
return;
}
logCallbackFmt[id] = proc;
}
void EQEMuLog::SetCallback(LogIDs id, msgCallbackBuf proc) {
if (!this)
return;
if (id >= MaxLogID) {
return;
}
logCallbackBuf[id] = proc;
}
void EQEMuLog::SetAllCallbacks(msgCallbackFmt proc) {
if (!this)
return;
int r;
for(r = Status; r < MaxLogID; r++) {
SetCallback((LogIDs)r, proc);
}
}
void EQEMuLog::SetAllCallbacks(msgCallbackBuf proc) {
if (!this)
return;
int r;
for(r = Status; r < MaxLogID; r++) {
SetCallback((LogIDs)r, proc);
}
}
*/

View File

@ -1,7 +1,13 @@
// Copyright (C) 2007-2025 EQ2EMulator
// Licensed under GPL v3
#ifndef EQDEBUG_H
#define EQDEBUG_H
#pragma once
#include <cstdio>
#include <cstdarg>
#include <cstdint>
#include <iostream>
#include <mutex>
// Debug Levels
/*
@ -16,55 +22,33 @@
#define EQDEBUG 1
#endif
#if defined(DEBUG) && defined(WIN32)
//#ifndef _CRTDBG_MAP_ALLOC
#include <stdlib.h>
#include <crtdbg.h>
#if (_MSC_VER < 1300)
#include <new>
#include <memory>
#define _CRTDBG_MAP_ALLOC
#define new new(_NORMAL_BLOCK, __FILE__, __LINE__)
#define malloc(s) _malloc_dbg(s, _NORMAL_BLOCK, __FILE__, __LINE__)
#endif
//#endif
#endif
#ifndef ThrowError
void CatchSignal(int);
#if defined(CATCH_CRASH) || defined(_EQDEBUG)
#define ThrowError(errstr) { cout << "Fatal error: " << errstr << " (" << __FILE__ << ", line " << __LINE__ << ")" << endl; LogWrite(WORLD__ERROR, 0, "Debug", "Thrown Error: %s (%s:%i)", errstr, __FILE__, __LINE__); throw errstr; }
#define ThrowError(errstr) { \
std::cout << "Fatal error: " << errstr << " (" << __FILE__ << ", line " << __LINE__ << ")" << std::endl; \
LogWrite(WORLD__ERROR, 0, "Debug", "Thrown Error: %s (%s:%i)", errstr, __FILE__, __LINE__); \
throw errstr; \
}
#else
#define ThrowError(errstr) { cout << "Fatal error: " << errstr << " (" << __FILE__ << ", line " << __LINE__ << ")" << endl; LogWrite(WORLD__ERROR, 0, "Debug", "Thrown Error: %s (%s:%i)", errstr, __FILE__, __LINE__); CatchSignal(0); }
#define ThrowError(errstr) { \
std::cout << "Fatal error: " << errstr << " (" << __FILE__ << ", line " << __LINE__ << ")" << std::endl; \
LogWrite(WORLD__ERROR, 0, "Debug", "Thrown Error: %s (%s:%i)", errstr, __FILE__, __LINE__); \
CatchSignal(0); \
}
#endif
#endif
#ifdef WIN32
// VS6 doesn't like the length of STL generated names: disabling
#pragma warning(disable:4786)
#endif
#define DebugBreak() if(0) {}
#ifndef WIN32
#define DebugBreak() if(0) {}
#endif
#ifdef WIN32
#include <WinSock2.h>
#include <windows.h>
#endif
#include "../common/Mutex.h"
#include <stdio.h>
#include <stdarg.h>
class EQEMuLog {
class EQEMuLog
{
public:
EQEMuLog();
~EQEMuLog();
enum LogIDs {
enum LogIDs
{
Status = 0, //this must stay the first entry in this list
Normal,
Error,
@ -74,53 +58,57 @@ public:
MaxLogID
};
//these are callbacks called for each
typedef void (* msgCallbackBuf)(LogIDs id, const char *buf, int8 size, int32 count);
typedef void (* msgCallbackFmt)(LogIDs id, const char *fmt, va_list ap);
// Callbacks called for each log entry
using msgCallbackBuf = void (*)(LogIDs id, const char* buf, std::int8_t size, std::int32_t count);
using msgCallbackFmt = void (*)(LogIDs id, const char* fmt, va_list ap);
void SetAllCallbacks(msgCallbackFmt proc);
void SetAllCallbacks(msgCallbackBuf proc);
void SetCallback(LogIDs id, msgCallbackFmt proc);
void SetCallback(LogIDs id, msgCallbackBuf proc);
bool writebuf(LogIDs id, const char *buf, int8 size, int32 count);
bool write(LogIDs id, const char *fmt, ...);
bool Dump(LogIDs id, int8* data, int32 size, int32 cols=16, int32 skip=0);
bool writebuf(LogIDs id, const char* buf, std::int8_t size, std::int32_t count);
bool write(LogIDs id, const char* fmt, ...);
bool Dump(LogIDs id, std::uint8_t* data, std::int32_t size, std::int32_t cols = 16, std::int32_t skip = 0);
private:
bool open(LogIDs id);
bool writeNTS(LogIDs id, bool dofile, const char *fmt, ...); // no error checking, assumes is open, no locking, no timestamp, no newline
bool writeNTS(LogIDs id, bool dofile, const char* fmt, ...); // no error checking, assumes is open, no locking, no timestamp, no newline
Mutex MOpen;
Mutex MLog[MaxLogID];
FILE* fp[MaxLogID];
/* LogStatus: bitwise variable
1 = output to file
2 = output to stdout
4 = fopen error, dont retry
8 = use stderr instead (2 must be set)
*/
int8 pLogStatus[MaxLogID];
std::mutex MOpen;
std::mutex MLog[MaxLogID];
FILE* fp[MaxLogID];
/* LogStatus: bitwise variable
1 = output to file
2 = output to stdout
4 = fopen error, dont retry
8 = use stderr instead (2 must be set)
*/
std::int8_t pLogStatus[MaxLogID];
msgCallbackFmt logCallbackFmt[MaxLogID];
msgCallbackBuf logCallbackBuf[MaxLogID];
};
//extern EQEMuLog* LogFile;
#ifdef _EQDEBUG
class PerformanceMonitor {
class PerformanceMonitor
{
public:
PerformanceMonitor(sint64* ip) {
PerformanceMonitor(std::int64_t* ip)
{
p = ip;
QueryPerformanceCounter(&tmp);
}
~PerformanceMonitor() {
~PerformanceMonitor()
{
LARGE_INTEGER tmp2;
QueryPerformanceCounter(&tmp2);
*p += tmp2.QuadPart - tmp.QuadPart;
}
LARGE_INTEGER tmp;
sint64* p;
std::int64_t* p;
};
#endif
#endif

16
source/common/defines.h Normal file
View File

@ -0,0 +1,16 @@
// Copyright (C) 2007-2025 EQ2EMulator
// Licensed under GPL v3
#define BASEDIR "./"
#ifndef DB_INI_FILE
#ifdef LOGIN
#define DB_INI_FILE BASEDIR "login_db.ini"
#else
#define DB_INI_FILE BASEDIR "world_db.ini"
#endif
#endif
#ifndef MAIN_CONFIG_FILE
#define MAIN_CONFIG_FILE BASEDIR "server_config.json"
#endif

238
source/common/mutex.cpp Normal file
View File

@ -0,0 +1,238 @@
// Copyright (C) 2007-2025 EQ2EMulator
// Licensed under GPL v3
#include "mutex.h"
// CriticalSection implementation
CriticalSection::CriticalSection(int attribute) : mutex_type(attribute)
{
if (mutex_type == MUTEX_ATTRIBUTE_RECURSIVE) {
recursive_mutex = std::make_unique<std::recursive_mutex>();
} else {
regular_mutex = std::make_unique<std::mutex>();
}
}
void CriticalSection::lock()
{
if (recursive_mutex) {
recursive_mutex->lock();
} else {
regular_mutex->lock();
}
}
void CriticalSection::unlock()
{
if (recursive_mutex) {
recursive_mutex->unlock();
} else {
regular_mutex->unlock();
}
}
bool CriticalSection::trylock()
{
if (recursive_mutex) {
return recursive_mutex->try_lock();
} else {
return regular_mutex->try_lock();
}
}
// Mutex implementation
Mutex::Mutex() : name("")
{
#ifdef DEBUG
stack.clear();
#endif
}
void Mutex::SetName(std::string in_name)
{
name = in_name;
}
void Mutex::lock()
{
#ifdef DEBUG
if (!name.empty()) {
auto start = std::chrono::steady_clock::now();
while (!basic_mutex.try_lock()) {
auto elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(
std::chrono::steady_clock::now() - start).count();
if (elapsed > MUTEX_TIMEOUT_MILLISECONDS) {
LogWrite(MUTEX__ERROR, 0, "Mutex", "Possible deadlock attempt by '%s'!", name.c_str());
return;
}
std::this_thread::sleep_for(std::chrono::milliseconds(1));
}
} else {
basic_mutex.lock();
}
#else
basic_mutex.lock();
#endif
}
bool Mutex::trylock()
{
return basic_mutex.try_lock();
}
void Mutex::unlock()
{
basic_mutex.unlock();
}
void Mutex::readlock([[maybe_unused]] const char* function, [[maybe_unused]] std::int32_t line)
{
#ifdef DEBUG
auto start = std::chrono::steady_clock::now();
while (!rw_mutex.try_lock_shared()) {
auto elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(
std::chrono::steady_clock::now() - start).count();
if (elapsed > MUTEX_TIMEOUT_MILLISECONDS) {
logDeadlock(function, line, "readlock");
start = std::chrono::steady_clock::now(); // Reset timer and continue
}
std::this_thread::sleep_for(std::chrono::milliseconds(1));
}
addDebugLock(function);
#else
rw_mutex.lock_shared();
#endif
}
void Mutex::releasereadlock([[maybe_unused]] const char* function, [[maybe_unused]] std::int32_t line)
{
rw_mutex.unlock_shared();
#ifdef DEBUG
removeDebugLock(function);
#endif
}
bool Mutex::tryreadlock([[maybe_unused]] const char* function)
{
bool result = rw_mutex.try_lock_shared();
#ifdef DEBUG
if (result && function) {
addDebugLock(function);
}
#endif
return result;
}
void Mutex::writelock([[maybe_unused]] const char* function, [[maybe_unused]] std::int32_t line)
{
#ifdef DEBUG
auto start = std::chrono::steady_clock::now();
while (!rw_mutex.try_lock()) {
auto elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(
std::chrono::steady_clock::now() - start).count();
if (elapsed > MUTEX_TIMEOUT_MILLISECONDS) {
logDeadlock(function, line, "writelock");
start = std::chrono::steady_clock::now(); // Reset timer and continue
}
std::this_thread::sleep_for(std::chrono::milliseconds(1));
}
addDebugLock(function);
#else
rw_mutex.lock();
#endif
}
void Mutex::releasewritelock([[maybe_unused]] const char* function, [[maybe_unused]] std::int32_t line)
{
rw_mutex.unlock();
#ifdef DEBUG
removeDebugLock(function);
#endif
}
bool Mutex::trywritelock([[maybe_unused]] const char* function)
{
bool result = rw_mutex.try_lock();
#ifdef DEBUG
if (result && function) {
addDebugLock(function);
}
#endif
return result;
}
void Mutex::waitReaders(const char* function, std::int32_t line)
{
// Wait until we can get a write lock (which means no readers)
writelock(function, line);
releasewritelock(function, line);
}
#ifdef DEBUG
void Mutex::addDebugLock(const char* function)
{
if (function) {
std::lock_guard<std::mutex> guard(debug_mutex);
stack[std::string(function)]++;
}
}
void Mutex::removeDebugLock(const char* function)
{
if (function) {
std::lock_guard<std::mutex> guard(debug_mutex);
auto itr = stack.find(std::string(function));
if (itr != stack.end()) {
if (--(itr->second) == 0) {
stack.erase(itr);
}
}
}
}
void Mutex::logDeadlock(const char* function, std::int32_t line, const char* lock_type)
{
LogWrite(MUTEX__ERROR, 0, "Mutex", "The mutex %s called from %s at line %u timed out waiting for a %s!",
name.c_str(), function ? function : "name_not_provided", line, lock_type);
LogWrite(MUTEX__ERROR, 0, "Mutex", "The following functions had locks:");
std::lock_guard<std::mutex> guard(debug_mutex);
for (const auto& [func_name, count] : stack) {
if (count > 0 && !func_name.empty()) {
LogWrite(MUTEX__ERROR, 0, "Mutex", "%s, number of locks = %u", func_name.c_str(), count);
}
}
}
#endif
// LockMutex implementation
LockMutex::LockMutex(Mutex* in_mut, bool iLock)
: locked(false), mut(in_mut)
{
if (mut && iLock) {
lock();
}
}
LockMutex::~LockMutex()
{
if (locked) {
unlock();
}
}
void LockMutex::lock()
{
if (mut && !locked) {
mut->lock();
locked = true;
}
}
void LockMutex::unlock()
{
if (mut && locked) {
mut->unlock();
locked = false;
}
}

83
source/common/mutex.h Normal file
View File

@ -0,0 +1,83 @@
// Copyright (C) 2007-2025 EQ2EMulator
// Licensed under GPL v3
#pragma once
#include <shared_mutex>
#include <mutex>
#include <string>
#include <map>
#include <cstdint>
#include <memory>
#include <chrono>
#define MUTEX_ATTRIBUTE_FAST 1
#define MUTEX_ATTRIBUTE_RECURSIVE 2
#define MUTEX_ATTRIBUTE_ERRORCHK 3
#define MUTEX_TIMEOUT_MILLISECONDS 10000
class CriticalSection
{
public:
CriticalSection(int attribute = MUTEX_ATTRIBUTE_FAST);
~CriticalSection() = default;
void lock();
void unlock();
bool trylock();
private:
std::unique_ptr<std::mutex> regular_mutex;
std::unique_ptr<std::recursive_mutex> recursive_mutex;
int mutex_type;
};
class Mutex
{
public:
Mutex();
~Mutex() = default;
void lock();
void unlock();
bool trylock();
void readlock(const char* function = nullptr, std::int32_t line = 0);
void releasereadlock(const char* function = nullptr, std::int32_t line = 0);
bool tryreadlock(const char* function = nullptr);
void writelock(const char* function = nullptr, std::int32_t line = 0);
void releasewritelock(const char* function = nullptr, std::int32_t line = 0);
bool trywritelock(const char* function = nullptr);
void waitReaders(const char* function = nullptr, std::int32_t line = 0);
void SetName(std::string in_name);
private:
std::shared_mutex rw_mutex;
std::mutex basic_mutex;
std::string name;
#ifdef DEBUG
std::mutex debug_mutex;
std::map<std::string, std::int32_t> stack;
void addDebugLock(const char* function);
void removeDebugLock(const char* function);
void logDeadlock(const char* function, std::int32_t line, const char* lock_type);
#endif
};
class LockMutex
{
public:
LockMutex(Mutex* in_mut, bool iLock = true);
~LockMutex();
void unlock();
void lock();
private:
bool locked;
Mutex* mut;
};

View File

@ -4,7 +4,7 @@
#define OPCODE_MANAGER_H
#include "types.h"
#include "Mutex.h"
#include "mutex.h"
#include "emu_opcodes.h"
#include <map>
@ -141,5 +141,3 @@ protected:
};
#endif