Core: Migrate SDL logging enhancements into core

This commit is contained in:
Vicki Pfau 2022-07-09 02:17:03 -07:00
parent f4f5521b9b
commit 8997055fc0
7 changed files with 111 additions and 100 deletions

View File

@ -36,6 +36,12 @@ struct mLogger {
struct mLogFilter* filter; struct mLogFilter* filter;
}; };
struct mStandardLogger {
struct mLogger d;
bool logToStdout;
struct VFile* logFile;
};
struct mLogger* mLogGetContext(void); struct mLogger* mLogGetContext(void);
void mLogSetDefaultLogger(struct mLogger*); void mLogSetDefaultLogger(struct mLogger*);
int mLogGenerateCategory(const char*, const char*); int mLogGenerateCategory(const char*, const char*);
@ -44,6 +50,10 @@ const char* mLogCategoryId(int);
int mLogCategoryById(const char*); int mLogCategoryById(const char*);
struct mCoreConfig; struct mCoreConfig;
void mStandardLoggerInit(struct mStandardLogger*);
void mStandardLoggerDeinit(struct mStandardLogger*);
void mStandardLoggerConfig(struct mStandardLogger*, struct mCoreConfig* config);
void mLogFilterInit(struct mLogFilter*); void mLogFilterInit(struct mLogFilter*);
void mLogFilterDeinit(struct mLogFilter*); void mLogFilterDeinit(struct mLogFilter*);
void mLogFilterLoad(struct mLogFilter*, const struct mCoreConfig*); void mLogFilterLoad(struct mLogFilter*, const struct mCoreConfig*);

View File

@ -21,6 +21,7 @@ struct mCoreThread;
struct mThreadLogger { struct mThreadLogger {
struct mLogger d; struct mLogger d;
struct mCoreThread* p; struct mCoreThread* p;
struct mLogger* logger;
}; };
#ifdef ENABLE_SCRIPTING #ifdef ENABLE_SCRIPTING

View File

@ -7,8 +7,10 @@
#include <mgba/core/config.h> #include <mgba/core/config.h>
#include <mgba/core/thread.h> #include <mgba/core/thread.h>
#include <mgba-util/vfs.h>
#define MAX_CATEGORY 64 #define MAX_CATEGORY 64
#define MAX_LOG_BUF 1024
static struct mLogger* _defaultLogger = NULL; static struct mLogger* _defaultLogger = NULL;
@ -183,4 +185,63 @@ int mLogFilterLevels(const struct mLogFilter* filter , int category) {
return value; return value;
} }
void _mCoreStandardLog(struct mLogger* logger, int category, enum mLogLevel level, const char* format, va_list args) {
struct mStandardLogger* stdlog = (struct mStandardLogger*) logger;
if (!mLogFilterTest(logger->filter, category, level)) {
return;
}
char buffer[MAX_LOG_BUF];
// Prepare the string
size_t length = snprintf(buffer, sizeof(buffer), "%s: ", mLogCategoryName(category));
if (length < sizeof(buffer)) {
length += vsnprintf(buffer + length, sizeof(buffer) - length, format, args);
}
if (length < sizeof(buffer)) {
length += snprintf(buffer + length, sizeof(buffer) - length, "\n");
}
// Make sure the length doesn't exceed the size of the buffer when actually writing
if (length > sizeof(buffer)) {
length = sizeof(buffer);
}
if (stdlog->logToStdout) {
printf("%s", buffer);
}
if (stdlog->logFile) {
stdlog->logFile->write(stdlog->logFile, buffer, length);
}
}
void mStandardLoggerInit(struct mStandardLogger* logger) {
logger->d.log = _mCoreStandardLog;
logger->d.filter = malloc(sizeof(struct mLogFilter));
mLogFilterInit(logger->d.filter);
}
void mStandardLoggerDeinit(struct mStandardLogger* logger) {
if (logger->d.filter) {
mLogFilterDeinit(logger->d.filter);
free(logger->d.filter);
logger->d.filter = NULL;
}
}
void mStandardLoggerConfig(struct mStandardLogger* logger, struct mCoreConfig* config) {
bool logToFile = false;
const char* logFile = mCoreConfigGetValue(config, "logFile");
mCoreConfigGetBoolValue(config, "logToStdout", &logger->logToStdout);
mCoreConfigGetBoolValue(config, "logToFile", &logToFile);
if (logToFile && logFile) {
logger->logFile = VFileOpen(logFile, O_WRONLY | O_CREAT | O_APPEND);
}
mLogFilterLoad(logger->d.filter, config);
}
mLOG_DEFINE_CATEGORY(STATUS, "Status", "core.status") mLOG_DEFINE_CATEGORY(STATUS, "Status", "core.status")

View File

@ -253,10 +253,13 @@ static THREAD_ENTRY _mCoreThreadRun(void* context) {
core->setSync(core, &threadContext->impl->sync); core->setSync(core, &threadContext->impl->sync);
struct mLogFilter filter; struct mLogFilter filter;
if (!threadContext->logger.d.filter) { struct mLogger* logger = &threadContext->logger.d;
threadContext->logger.d.filter = &filter; if (threadContext->logger.logger) {
mLogFilterInit(threadContext->logger.d.filter); logger->filter = threadContext->logger.logger->filter;
mLogFilterLoad(threadContext->logger.d.filter, &core->config); } else {
logger->filter = &filter;
mLogFilterInit(logger->filter);
mLogFilterLoad(logger->filter, &core->config);
} }
#ifdef ENABLE_SCRIPTING #ifdef ENABLE_SCRIPTING
@ -431,10 +434,10 @@ static THREAD_ENTRY _mCoreThreadRun(void* context) {
#endif #endif
core->clearCoreCallbacks(core); core->clearCoreCallbacks(core);
if (threadContext->logger.d.filter == &filter) { if (logger->filter == &filter) {
mLogFilterDeinit(&filter); mLogFilterDeinit(&filter);
} }
threadContext->logger.d.filter = NULL; logger->filter = NULL;
return 0; return 0;
} }
@ -444,10 +447,8 @@ bool mCoreThreadStart(struct mCoreThread* threadContext) {
threadContext->impl->state = mTHREAD_INITIALIZED; threadContext->impl->state = mTHREAD_INITIALIZED;
threadContext->impl->requested = 0; threadContext->impl->requested = 0;
threadContext->logger.p = threadContext; threadContext->logger.p = threadContext;
if (!threadContext->logger.d.log) { threadContext->logger.d.log = _mCoreLog;
threadContext->logger.d.log = _mCoreLog; threadContext->logger.d.filter = NULL;
threadContext->logger.d.filter = NULL;
}
if (!threadContext->impl->sync.fpsTarget) { if (!threadContext->impl->sync.fpsTarget) {
threadContext->impl->sync.fpsTarget = _defaultFPSTarget; threadContext->impl->sync.fpsTarget = _defaultFPSTarget;
@ -718,14 +719,17 @@ struct mCoreThread* mCoreThreadGet(void) {
} }
static void _mCoreLog(struct mLogger* logger, int category, enum mLogLevel level, const char* format, va_list args) { static void _mCoreLog(struct mLogger* logger, int category, enum mLogLevel level, const char* format, va_list args) {
UNUSED(logger); struct mThreadLogger* threadLogger = (struct mThreadLogger*) logger;
UNUSED(level); if (level == mLOG_FATAL) {
printf("%s: ", mLogCategoryName(category)); mCoreThreadMarkCrashed(threadLogger->p);
vprintf(format, args); }
printf("\n"); if (!threadLogger->p->logger.logger) {
struct mCoreThread* thread = mCoreThreadGet(); printf("%s: ", mLogCategoryName(category));
if (thread && level == mLOG_FATAL) { vprintf(format, args);
mCoreThreadMarkCrashed(thread); printf("\n");
} else {
logger = threadLogger->p->logger.logger;
logger->log(logger, category, level, format, args);
} }
} }
#else #else

View File

@ -144,19 +144,19 @@ CoreController::CoreController(mCore* core, QObject* parent)
QMetaObject::invokeMethod(controller, "unpaused"); QMetaObject::invokeMethod(controller, "unpaused");
}; };
m_threadContext.logger.d.log = [](mLogger* logger, int category, enum mLogLevel level, const char* format, va_list args) { m_logger.self = this;
mThreadLogger* logContext = reinterpret_cast<mThreadLogger*>(logger); m_logger.log = [](mLogger* logger, int category, enum mLogLevel level, const char* format, va_list args) {
mCoreThread* context = logContext->p; CoreLogger* logContext = static_cast<CoreLogger*>(logger);
static const char* savestateMessage = "State %i saved"; static const char* savestateMessage = "State %i saved";
static const char* loadstateMessage = "State %i loaded"; static const char* loadstateMessage = "State %i loaded";
static const char* savestateFailedMessage = "State %i failed to load"; static const char* savestateFailedMessage = "State %i failed to load";
static int biosCat = -1; static int biosCat = -1;
static int statusCat = -1; static int statusCat = -1;
if (!context) { if (!logContext) {
return; return;
} }
CoreController* controller = static_cast<CoreController*>(context->userData); CoreController* controller = logContext->self;
QString message; QString message;
if (biosCat < 0) { if (biosCat < 0) {
biosCat = mLogCategoryById("gba.bios"); biosCat = mLogCategoryById("gba.bios");
@ -201,10 +201,10 @@ CoreController::CoreController(mCore* core, QObject* parent)
message = QString::vasprintf(format, args); message = QString::vasprintf(format, args);
QMetaObject::invokeMethod(controller, "logPosted", Q_ARG(int, level), Q_ARG(int, category), Q_ARG(const QString&, message)); QMetaObject::invokeMethod(controller, "logPosted", Q_ARG(int, level), Q_ARG(int, category), Q_ARG(const QString&, message));
if (level == mLOG_FATAL) { if (level == mLOG_FATAL) {
mCoreThreadMarkCrashed(controller->thread());
QMetaObject::invokeMethod(controller, "crashed", Q_ARG(const QString&, message)); QMetaObject::invokeMethod(controller, "crashed", Q_ARG(const QString&, message));
} }
}; };
m_threadContext.logger.logger = &m_logger;
} }
CoreController::~CoreController() { CoreController::~CoreController() {
@ -424,7 +424,7 @@ void CoreController::setInputController(InputController* inputController) {
void CoreController::setLogger(LogController* logger) { void CoreController::setLogger(LogController* logger) {
disconnect(m_log); disconnect(m_log);
m_log = logger; m_log = logger;
m_threadContext.logger.d.filter = logger->filter(); m_logger.filter = logger->filter();
connect(this, &CoreController::logPosted, m_log, &LogController::postLog); connect(this, &CoreController::logPosted, m_log, &LogController::postLog);
} }

View File

@ -241,6 +241,9 @@ private:
void updateROMInfo(); void updateROMInfo();
mCoreThread m_threadContext{}; mCoreThread m_threadContext{};
struct CoreLogger : public mLogger {
CoreController* self;
} m_logger{};
bool m_patched = false; bool m_patched = false;
bool m_preload = false; bool m_preload = false;

View File

@ -38,19 +38,12 @@
#include <signal.h> #include <signal.h>
#define PORT "sdl" #define PORT "sdl"
#define MAX_LOG_BUF 1024
static void mSDLDeinit(struct mSDLRenderer* renderer); static void mSDLDeinit(struct mSDLRenderer* renderer);
static int mSDLRun(struct mSDLRenderer* renderer, struct mArguments* args); static int mSDLRun(struct mSDLRenderer* renderer, struct mArguments* args);
static void _setLogger(struct mCore* core); static struct mStandardLogger _logger;
static void _mCoreLog(struct mLogger* logger, int category, enum mLogLevel level, const char* format, va_list args);
static bool _logToStdout = true;
static struct VFile* _logFile = NULL;
static struct mLogFilter _filter;
static struct mLogger _logger;
static struct VFile* _state = NULL; static struct VFile* _state = NULL;
@ -136,6 +129,7 @@ int main(int argc, char** argv) {
mCoreInitConfig(renderer.core, PORT); mCoreInitConfig(renderer.core, PORT);
mArgumentsApply(&args, &subparser, 1, &renderer.core->config); mArgumentsApply(&args, &subparser, 1, &renderer.core->config);
mCoreConfigSetDefaultIntValue(&renderer.core->config, "logToStdout", true);
mCoreConfigLoadDefaults(&renderer.core->config, &opts); mCoreConfigLoadDefaults(&renderer.core->config, &opts);
mCoreLoadConfig(renderer.core); mCoreLoadConfig(renderer.core);
@ -188,7 +182,8 @@ int main(int argc, char** argv) {
int ret; int ret;
// TODO: Use opts and config // TODO: Use opts and config
_setLogger(renderer.core); mStandardLoggerInit(&_logger);
mStandardLoggerConfig(&_logger, &renderer.core->config);
ret = mSDLRun(&renderer, &args); ret = mSDLRun(&renderer, &args);
mSDLDetachPlayer(&renderer.events, &renderer.player); mSDLDetachPlayer(&renderer.events, &renderer.player);
mInputMapDeinit(&renderer.core->inputMap); mInputMapDeinit(&renderer.core->inputMap);
@ -198,6 +193,7 @@ int main(int argc, char** argv) {
} }
mSDLDeinit(&renderer); mSDLDeinit(&renderer);
mStandardLoggerDeinit(&_logger);
mArgumentsDeinit(&args); mArgumentsDeinit(&args);
mCoreConfigFreeOpts(&opts); mCoreConfigFreeOpts(&opts);
@ -273,12 +269,8 @@ int mSDLRun(struct mSDLRenderer* renderer, struct mArguments* args) {
renderer->audio.samples = renderer->core->opts.audioBuffers; renderer->audio.samples = renderer->core->opts.audioBuffers;
renderer->audio.sampleRate = 44100; renderer->audio.sampleRate = 44100;
thread.logger.logger = &_logger.d;
struct mThreadLogger threadLogger;
threadLogger.d = _logger;
threadLogger.p = &thread;
thread.logger = threadLogger;
bool didFail = !mCoreThreadStart(&thread); bool didFail = !mCoreThreadStart(&thread);
if (!didFail) { if (!didFail) {
@ -342,63 +334,3 @@ static void mSDLDeinit(struct mSDLRenderer* renderer) {
SDL_Quit(); SDL_Quit();
} }
static void _setLogger(struct mCore* core) {
int fakeBool = 0;
bool logToFile = false;
if (mCoreConfigGetIntValue(&core->config, "logToStdout", &fakeBool)) {
_logToStdout = fakeBool;
}
if (mCoreConfigGetIntValue(&core->config, "logToFile", &fakeBool)) {
logToFile = fakeBool;
}
const char* logFile = mCoreConfigGetValue(&core->config, "logFile");
if (logToFile && logFile) {
_logFile = VFileOpen(logFile, O_WRONLY | O_CREAT | O_APPEND);
}
// Create the filter
mLogFilterInit(&_filter);
mLogFilterLoad(&_filter, &core->config);
// Fill the logger
_logger.log = _mCoreLog;
_logger.filter = &_filter;
}
static void _mCoreLog(struct mLogger* logger, int category, enum mLogLevel level, const char* format, va_list args) {
struct mCoreThread* thread = mCoreThreadGet();
if (thread && level == mLOG_FATAL) {
mCoreThreadMarkCrashed(thread);
}
if (!mLogFilterTest(logger->filter, category, level)) {
return;
}
char buffer[MAX_LOG_BUF];
// Prepare the string
size_t length = snprintf(buffer, sizeof(buffer), "%s: ", mLogCategoryName(category));
if (length < sizeof(buffer)) {
length += vsnprintf(buffer + length, sizeof(buffer) - length, format, args);
}
if (length < sizeof(buffer)) {
length += snprintf(buffer + length, sizeof(buffer) - length, "\n");
}
// Make sure the length doesn't exceed the size of the buffer when actually writing
if (length > sizeof(buffer)) {
length = sizeof(buffer);
}
if (_logToStdout) {
printf("%s", buffer);
}
if (_logFile) {
_logFile->write(_logFile, buffer, length);
}
}