Files
djhackersdev_bemanitools/src/main/iidxhook-util/log-server.c
T
icex2 ed34be6ec3 wip frame pacing code
Summary:

Test Plan:
2025-01-20 20:13:57 +01:00

166 lines
4.3 KiB
C

#include <windows.h>
#include <stdarg.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include "hook/table.h"
#include "iidxhook-util/log-server.h"
#include "imports/avs.h"
#include "util/defs.h"
#include "util/log.h"
#include "util/str.h"
#include "util/thread.h"
static int log_thread_proc(void *ctx);
static void
log_post(char level, const char *module, const char *fmt, va_list ap);
static void log_post_misc(const char *module, const char *fmt, ...);
static void log_post_info(const char *module, const char *fmt, ...);
static void log_post_warning(const char *module, const char *fmt, ...);
static void log_post_fatal(const char *module, const char *fmt, ...);
static int log_thread_id;
static HANDLE log_rv_producer;
static HANDLE log_rv_consumer;
static char log_rv_level;
static const char *log_rv_module;
static char log_rv_buffer[8192];
void log_server_init(void)
{
HANDLE ready;
log_rv_producer = CreateSemaphore(NULL, 1, 1, NULL);
log_rv_consumer = CreateSemaphore(NULL, 0, 1, NULL);
ready = CreateEvent(NULL, TRUE, FALSE, NULL);
log_to_external(
log_post_misc, log_post_info, log_post_warning, log_post_fatal);
log_thread_id = avs_thread_create(log_thread_proc, ready, 16384, 0);
if (WaitForSingleObject(ready, INFINITE)) {
// can't do any logging here, yet.
fprintf(
stderr,
"ERROR log_server_init: WaitForSingleObject failed: %08x",
(unsigned int) GetLastError());
return;
}
CloseHandle(ready);
log_misc("Started log server thread");
}
static int log_thread_proc(void *ctx)
{
bool run;
SetEvent((HANDLE) ctx);
run = true;
log_body_misc(LOG_MODULE, "Log server thread is running");
while (run) {
if (WaitForSingleObject(log_rv_consumer, INFINITE)) {
log_fatal(
"WaitForSingleObject failed: %08x",
(unsigned int) GetLastError());
}
switch (log_rv_level) {
case '\0':
run = false;
break;
case 'M':
log_body_misc(log_rv_module, "%s", log_rv_buffer);
break;
case 'I':
log_body_info(log_rv_module, "%s", log_rv_buffer);
break;
case 'W':
log_body_warning(log_rv_module, "%s", log_rv_buffer);
break;
case 'F':
log_body_fatal(log_rv_module, "%s", log_rv_buffer);
break;
}
if (!ReleaseSemaphore(log_rv_producer, 1, NULL)) {
log_fatal(
"ReleaseSemaphore failed: %08x", (unsigned int) GetLastError());
}
}
log_body_misc(LOG_MODULE, "Log server thread is exiting");
return 0;
}
static void
log_post(char level, const char *module, const char *fmt, va_list ap)
{
// TODO test if this addresses performance issues and stuttering
// TODO measure time how long waiting takes here?
if (WaitForSingleObject(log_rv_producer, INFINITE)) {
return;
}
log_rv_level = level;
log_rv_module = module;
str_vformat(log_rv_buffer, sizeof(log_rv_buffer), fmt, ap);
ReleaseSemaphore(log_rv_consumer, 1, NULL);
}
#define LOG_POST_IMPL(name, level) \
static void name(const char *module, const char *fmt, ...) \
{ \
va_list ap; \
\
va_start(ap, fmt); \
log_post(level, module, fmt, ap); \
va_end(ap); \
}
LOG_POST_IMPL(log_post_misc, 'M')
LOG_POST_IMPL(log_post_info, 'I')
LOG_POST_IMPL(log_post_warning, 'W')
LOG_POST_IMPL(log_post_fatal, 'F')
void log_server_fini(void)
{
int thread_result;
log_misc("Stopping log server thread");
WaitForSingleObject(log_rv_producer, INFINITE);
log_rv_level = '\0';
ReleaseSemaphore(log_rv_consumer, 1, NULL);
avs_thread_join(log_thread_id, &thread_result);
avs_thread_destroy(log_thread_id);
CloseHandle(log_rv_producer);
CloseHandle(log_rv_consumer);
log_rv_producer = NULL;
log_rv_consumer = NULL;
}