mirror of https://github.com/mgba-emu/mgba.git
Core: Migrate SDL logging enhancements into core
This commit is contained in:
parent
f4f5521b9b
commit
8997055fc0
|
@ -36,6 +36,12 @@ struct mLogger {
|
|||
struct mLogFilter* filter;
|
||||
};
|
||||
|
||||
struct mStandardLogger {
|
||||
struct mLogger d;
|
||||
bool logToStdout;
|
||||
struct VFile* logFile;
|
||||
};
|
||||
|
||||
struct mLogger* mLogGetContext(void);
|
||||
void mLogSetDefaultLogger(struct mLogger*);
|
||||
int mLogGenerateCategory(const char*, const char*);
|
||||
|
@ -44,6 +50,10 @@ const char* mLogCategoryId(int);
|
|||
int mLogCategoryById(const char*);
|
||||
|
||||
struct mCoreConfig;
|
||||
void mStandardLoggerInit(struct mStandardLogger*);
|
||||
void mStandardLoggerDeinit(struct mStandardLogger*);
|
||||
void mStandardLoggerConfig(struct mStandardLogger*, struct mCoreConfig* config);
|
||||
|
||||
void mLogFilterInit(struct mLogFilter*);
|
||||
void mLogFilterDeinit(struct mLogFilter*);
|
||||
void mLogFilterLoad(struct mLogFilter*, const struct mCoreConfig*);
|
||||
|
|
|
@ -21,6 +21,7 @@ struct mCoreThread;
|
|||
struct mThreadLogger {
|
||||
struct mLogger d;
|
||||
struct mCoreThread* p;
|
||||
struct mLogger* logger;
|
||||
};
|
||||
|
||||
#ifdef ENABLE_SCRIPTING
|
||||
|
|
|
@ -7,8 +7,10 @@
|
|||
|
||||
#include <mgba/core/config.h>
|
||||
#include <mgba/core/thread.h>
|
||||
#include <mgba-util/vfs.h>
|
||||
|
||||
#define MAX_CATEGORY 64
|
||||
#define MAX_LOG_BUF 1024
|
||||
|
||||
static struct mLogger* _defaultLogger = NULL;
|
||||
|
||||
|
@ -183,4 +185,63 @@ int mLogFilterLevels(const struct mLogFilter* filter , int category) {
|
|||
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")
|
||||
|
|
|
@ -253,10 +253,13 @@ static THREAD_ENTRY _mCoreThreadRun(void* context) {
|
|||
core->setSync(core, &threadContext->impl->sync);
|
||||
|
||||
struct mLogFilter filter;
|
||||
if (!threadContext->logger.d.filter) {
|
||||
threadContext->logger.d.filter = &filter;
|
||||
mLogFilterInit(threadContext->logger.d.filter);
|
||||
mLogFilterLoad(threadContext->logger.d.filter, &core->config);
|
||||
struct mLogger* logger = &threadContext->logger.d;
|
||||
if (threadContext->logger.logger) {
|
||||
logger->filter = threadContext->logger.logger->filter;
|
||||
} else {
|
||||
logger->filter = &filter;
|
||||
mLogFilterInit(logger->filter);
|
||||
mLogFilterLoad(logger->filter, &core->config);
|
||||
}
|
||||
|
||||
#ifdef ENABLE_SCRIPTING
|
||||
|
@ -431,10 +434,10 @@ static THREAD_ENTRY _mCoreThreadRun(void* context) {
|
|||
#endif
|
||||
core->clearCoreCallbacks(core);
|
||||
|
||||
if (threadContext->logger.d.filter == &filter) {
|
||||
if (logger->filter == &filter) {
|
||||
mLogFilterDeinit(&filter);
|
||||
}
|
||||
threadContext->logger.d.filter = NULL;
|
||||
logger->filter = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -444,10 +447,8 @@ bool mCoreThreadStart(struct mCoreThread* threadContext) {
|
|||
threadContext->impl->state = mTHREAD_INITIALIZED;
|
||||
threadContext->impl->requested = 0;
|
||||
threadContext->logger.p = threadContext;
|
||||
if (!threadContext->logger.d.log) {
|
||||
threadContext->logger.d.log = _mCoreLog;
|
||||
threadContext->logger.d.filter = NULL;
|
||||
}
|
||||
threadContext->logger.d.log = _mCoreLog;
|
||||
threadContext->logger.d.filter = NULL;
|
||||
|
||||
if (!threadContext->impl->sync.fpsTarget) {
|
||||
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) {
|
||||
UNUSED(logger);
|
||||
UNUSED(level);
|
||||
printf("%s: ", mLogCategoryName(category));
|
||||
vprintf(format, args);
|
||||
printf("\n");
|
||||
struct mCoreThread* thread = mCoreThreadGet();
|
||||
if (thread && level == mLOG_FATAL) {
|
||||
mCoreThreadMarkCrashed(thread);
|
||||
struct mThreadLogger* threadLogger = (struct mThreadLogger*) logger;
|
||||
if (level == mLOG_FATAL) {
|
||||
mCoreThreadMarkCrashed(threadLogger->p);
|
||||
}
|
||||
if (!threadLogger->p->logger.logger) {
|
||||
printf("%s: ", mLogCategoryName(category));
|
||||
vprintf(format, args);
|
||||
printf("\n");
|
||||
} else {
|
||||
logger = threadLogger->p->logger.logger;
|
||||
logger->log(logger, category, level, format, args);
|
||||
}
|
||||
}
|
||||
#else
|
||||
|
|
|
@ -144,19 +144,19 @@ CoreController::CoreController(mCore* core, QObject* parent)
|
|||
QMetaObject::invokeMethod(controller, "unpaused");
|
||||
};
|
||||
|
||||
m_threadContext.logger.d.log = [](mLogger* logger, int category, enum mLogLevel level, const char* format, va_list args) {
|
||||
mThreadLogger* logContext = reinterpret_cast<mThreadLogger*>(logger);
|
||||
mCoreThread* context = logContext->p;
|
||||
m_logger.self = this;
|
||||
m_logger.log = [](mLogger* logger, int category, enum mLogLevel level, const char* format, va_list args) {
|
||||
CoreLogger* logContext = static_cast<CoreLogger*>(logger);
|
||||
|
||||
static const char* savestateMessage = "State %i saved";
|
||||
static const char* loadstateMessage = "State %i loaded";
|
||||
static const char* savestateFailedMessage = "State %i failed to load";
|
||||
static int biosCat = -1;
|
||||
static int statusCat = -1;
|
||||
if (!context) {
|
||||
if (!logContext) {
|
||||
return;
|
||||
}
|
||||
CoreController* controller = static_cast<CoreController*>(context->userData);
|
||||
CoreController* controller = logContext->self;
|
||||
QString message;
|
||||
if (biosCat < 0) {
|
||||
biosCat = mLogCategoryById("gba.bios");
|
||||
|
@ -201,10 +201,10 @@ CoreController::CoreController(mCore* core, QObject* parent)
|
|||
message = QString::vasprintf(format, args);
|
||||
QMetaObject::invokeMethod(controller, "logPosted", Q_ARG(int, level), Q_ARG(int, category), Q_ARG(const QString&, message));
|
||||
if (level == mLOG_FATAL) {
|
||||
mCoreThreadMarkCrashed(controller->thread());
|
||||
QMetaObject::invokeMethod(controller, "crashed", Q_ARG(const QString&, message));
|
||||
}
|
||||
};
|
||||
m_threadContext.logger.logger = &m_logger;
|
||||
}
|
||||
|
||||
CoreController::~CoreController() {
|
||||
|
@ -424,7 +424,7 @@ void CoreController::setInputController(InputController* inputController) {
|
|||
void CoreController::setLogger(LogController* logger) {
|
||||
disconnect(m_log);
|
||||
m_log = logger;
|
||||
m_threadContext.logger.d.filter = logger->filter();
|
||||
m_logger.filter = logger->filter();
|
||||
connect(this, &CoreController::logPosted, m_log, &LogController::postLog);
|
||||
}
|
||||
|
||||
|
|
|
@ -241,6 +241,9 @@ private:
|
|||
void updateROMInfo();
|
||||
|
||||
mCoreThread m_threadContext{};
|
||||
struct CoreLogger : public mLogger {
|
||||
CoreController* self;
|
||||
} m_logger{};
|
||||
|
||||
bool m_patched = false;
|
||||
bool m_preload = false;
|
||||
|
|
|
@ -38,19 +38,12 @@
|
|||
#include <signal.h>
|
||||
|
||||
#define PORT "sdl"
|
||||
#define MAX_LOG_BUF 1024
|
||||
|
||||
static void mSDLDeinit(struct mSDLRenderer* renderer);
|
||||
|
||||
static int mSDLRun(struct mSDLRenderer* renderer, struct mArguments* args);
|
||||
|
||||
static void _setLogger(struct mCore* core);
|
||||
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 mStandardLogger _logger;
|
||||
|
||||
static struct VFile* _state = NULL;
|
||||
|
||||
|
@ -136,6 +129,7 @@ int main(int argc, char** argv) {
|
|||
mCoreInitConfig(renderer.core, PORT);
|
||||
mArgumentsApply(&args, &subparser, 1, &renderer.core->config);
|
||||
|
||||
mCoreConfigSetDefaultIntValue(&renderer.core->config, "logToStdout", true);
|
||||
mCoreConfigLoadDefaults(&renderer.core->config, &opts);
|
||||
mCoreLoadConfig(renderer.core);
|
||||
|
||||
|
@ -188,7 +182,8 @@ int main(int argc, char** argv) {
|
|||
int ret;
|
||||
|
||||
// TODO: Use opts and config
|
||||
_setLogger(renderer.core);
|
||||
mStandardLoggerInit(&_logger);
|
||||
mStandardLoggerConfig(&_logger, &renderer.core->config);
|
||||
ret = mSDLRun(&renderer, &args);
|
||||
mSDLDetachPlayer(&renderer.events, &renderer.player);
|
||||
mInputMapDeinit(&renderer.core->inputMap);
|
||||
|
@ -198,6 +193,7 @@ int main(int argc, char** argv) {
|
|||
}
|
||||
|
||||
mSDLDeinit(&renderer);
|
||||
mStandardLoggerDeinit(&_logger);
|
||||
|
||||
mArgumentsDeinit(&args);
|
||||
mCoreConfigFreeOpts(&opts);
|
||||
|
@ -273,11 +269,7 @@ int mSDLRun(struct mSDLRenderer* renderer, struct mArguments* args) {
|
|||
|
||||
renderer->audio.samples = renderer->core->opts.audioBuffers;
|
||||
renderer->audio.sampleRate = 44100;
|
||||
|
||||
struct mThreadLogger threadLogger;
|
||||
threadLogger.d = _logger;
|
||||
threadLogger.p = &thread;
|
||||
thread.logger = threadLogger;
|
||||
thread.logger.logger = &_logger.d;
|
||||
|
||||
bool didFail = !mCoreThreadStart(&thread);
|
||||
|
||||
|
@ -342,63 +334,3 @@ static void mSDLDeinit(struct mSDLRenderer* renderer) {
|
|||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue