Skip to content

Commit 6940a9d

Browse files
author
icex2
committed
feat: Add core module
This module contains the "core" (API) of bemanitools which includes an abstraction layer for threads and logging at this time. The threads API is very close to what util/thread already was with some structural enhancements which make it easier to understand and work with the API, I hope. Some additional helpers (*-ext module) support in doing common tasks, e.g. setting up the thread API with other modules. The log(ging) part receives a major overhaul to address known limitations and issues with the util/log module: - Cleaner API layer - Separate sinks from actual logging engine - Sinks are composable - Improved and cleaner compatibility layer with AVS logging API Additional "extensions" (*-ext modules) add various helper functions for common tasks like setting up the logging engine with a file and stdout sink. The sinks also improved significantly with the file sink now supporting proper appending and log rotation. Logging to stdout/stderr supports coloring of log messages which works across logging engines. Overall, this refactored foundation is expected to support future developments and removes known limitations at the current scale of bemanitools such as: - Reducing boiler plate code across hooks - Interop of bemanitools and AVS (and setting the foundation for addressing currently missing interop, e.g. for dealing with property structures without AVS) - Addressing performance issues in the logging engine due to incorrect interop with AVS
1 parent 1d48964 commit 6940a9d

29 files changed

Lines changed: 1587 additions & 0 deletions

‎Module.mk‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,7 @@ include src/main/bstio/Module.mk
100100
include src/main/camhook/Module.mk
101101
include src/main/cconfig/Module.mk
102102
include src/main/config/Module.mk
103+
include src/main/core/Module.mk
103104
include src/main/d3d9-util/Module.mk
104105
include src/main/d3d9exhook/Module.mk
105106
include src/main/ddrhook-util/Module.mk

‎src/main/core/Module.mk‎

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
libs += core
2+
3+
libs_core := \
4+
util \
5+
6+
src_core := \
7+
log-bt-ext.c \
8+
log-bt.c \
9+
log-sink-async.c \
10+
log-sink-debug.c \
11+
log-sink-file.c \
12+
log-sink-list.c \
13+
log-sink-mutex.c \
14+
log-sink-null.c \
15+
log-sink-std.c \
16+
log.c \
17+
thread-crt-ext.c \
18+
thread-crt.c \
19+
thread.c \
20+

‎src/main/core/log-bt-ext.c‎

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
#include <stdbool.h>
2+
3+
#include "core/log-bt.h"
4+
#include "core/log-sink-debug.h"
5+
#include "core/log-sink-file.h"
6+
#include "core/log-sink-list.h"
7+
#include "core/log-sink-mutex.h"
8+
#include "core/log-sink-std.h"
9+
#include "core/log.h"
10+
11+
void core_log_bt_ext_impl_set()
12+
{
13+
core_log_impl_set(
14+
core_log_bt_log_misc,
15+
core_log_bt_log_info,
16+
core_log_bt_log_warning,
17+
core_log_bt_log_fatal);
18+
}
19+
20+
void core_log_bt_ext_init_with_stdout()
21+
{
22+
struct core_log_sink sink;
23+
24+
core_log_sink_std_out_open(true, &sink);
25+
core_log_bt_init(&sink);
26+
}
27+
28+
void core_log_bt_ext_init_with_stderr()
29+
{
30+
struct core_log_sink sink;
31+
32+
core_log_sink_std_err_open(true, &sink);
33+
core_log_bt_init(&sink);
34+
}
35+
36+
void core_log_bt_ext_init_with_debug()
37+
{
38+
struct core_log_sink sink;
39+
40+
core_log_sink_debug_open(&sink);
41+
core_log_bt_init(&sink);
42+
}
43+
44+
void core_log_bt_ext_init_with_file(
45+
const char *path, bool append, bool rotate, uint8_t max_rotations)
46+
{
47+
struct core_log_sink sink;
48+
49+
core_log_sink_file_open(path, append, rotate, max_rotations, &sink);
50+
core_log_bt_init(&sink);
51+
}
52+
53+
void core_log_bt_ext_init_with_stdout_and_file(
54+
const char *path, bool append, bool rotate, uint8_t max_rotations)
55+
{
56+
struct core_log_sink sinks[2];
57+
struct core_log_sink sink_composed;
58+
struct core_log_sink sink_mutex;
59+
60+
core_log_sink_std_out_open(true, &sinks[0]);
61+
core_log_sink_file_open(path, append, rotate, max_rotations, &sinks[1]);
62+
core_log_sink_list_open(sinks, 2, &sink_composed);
63+
64+
core_log_sink_mutex_open(&sink_composed, &sink_mutex);
65+
66+
core_log_bt_init(&sink_mutex);
67+
}

‎src/main/core/log-bt-ext.h‎

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
#ifndef CORE_LOG_BT_EXT_H
2+
#define CORE_LOG_BT_EXT_H
3+
4+
#include <stdbool.h>
5+
#include <stdint.h>
6+
7+
/**
8+
* Set the current thread API implementation to use the bemanitools log
9+
* implementation
10+
*/
11+
void core_log_bt_ext_impl_set();
12+
13+
/**
14+
* Helper to setup the bemanitools log implementation with a stdout sink.
15+
*/
16+
void core_log_bt_ext_init_with_stdout();
17+
18+
/**
19+
* Helper to setup the bemanitools log implementation with a stderr sink.
20+
*/
21+
void core_log_bt_ext_init_with_stderr();
22+
23+
/**
24+
* Helper to setup the bemanitools log implementation with a OutputDebugStr
25+
* sink.
26+
*/
27+
void core_log_bt_ext_init_with_debug();
28+
29+
/**
30+
* Helper to setup the bemanitools log implementation with a file sink
31+
*
32+
* @param path Path to the log file to write the log output to
33+
* @param append If true, then append to an existing file, false to overwrite
34+
* any existing file
35+
* @param rotate If true, rotates an existing log file and creates a new one
36+
* for this session
37+
* @param max_rotations Max number of rotations for the log files
38+
*/
39+
void core_log_bt_ext_init_with_file(
40+
const char *path, bool append, bool rotate, uint8_t max_rotations);
41+
42+
/**
43+
* Helper to setup the bemanitools log implementation with a stdout and file
44+
* sink
45+
*
46+
* Important: This combined sink is guarded by a mutex to avoid data races on
47+
* logging to two different sinks.
48+
*
49+
* @param path Path to the log file to write the log output to
50+
* @param append If true, then append to an existing file, false to overwrite
51+
* any existing file
52+
* @param rotate If true, rotates an existing log file and creates a new one
53+
* for this session
54+
* @param max_rotations Max number of rotations for the log files
55+
*/
56+
void core_log_bt_ext_init_with_stdout_and_file(
57+
const char *path, bool append, bool rotate, uint8_t max_rotations);
58+
59+
#endif

‎src/main/core/log-bt.c‎

Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
#include <stdarg.h>
2+
#include <stdlib.h>
3+
#include <time.h>
4+
5+
#include "core/log-bt.h"
6+
#include "core/log-sink.h"
7+
#include "core/log.h"
8+
9+
#include "util/mem.h"
10+
#include "util/str.h"
11+
12+
static enum core_log_bt_log_level _core_log_bt_log_level;
13+
static struct core_log_sink *_core_log_bt_sink;
14+
15+
static void _core_log_bt_vformat_write(
16+
enum core_log_bt_log_level level,
17+
const char *module,
18+
const char *fmt,
19+
va_list ap)
20+
{
21+
static const char chars[] = "FFWIM";
22+
23+
char timestamp[64];
24+
/* 64k so we can log data dumps of rs232 without crashing */
25+
char msg[65536];
26+
char line[65536];
27+
int result;
28+
29+
time_t curtime;
30+
struct tm *tm;
31+
32+
curtime = 0;
33+
tm = NULL;
34+
35+
curtime = time(NULL);
36+
tm = localtime(&curtime);
37+
38+
strftime(timestamp, sizeof(timestamp), "[%Y/%m/%d %H:%M:%S]", tm);
39+
40+
str_vformat(msg, sizeof(msg), fmt, ap);
41+
42+
result = str_format(
43+
line,
44+
sizeof(line),
45+
"%s %c:%s: %s\n",
46+
timestamp,
47+
chars[level],
48+
module,
49+
msg);
50+
51+
_core_log_bt_sink->write(_core_log_bt_sink->ctx, line, result);
52+
}
53+
54+
void core_log_bt_init(const struct core_log_sink *sink)
55+
{
56+
if (sink == NULL) {
57+
abort();
58+
}
59+
60+
_core_log_bt_sink = xmalloc(sizeof(struct core_log_sink));
61+
memcpy(_core_log_bt_sink, sink, sizeof(struct core_log_sink));
62+
63+
_core_log_bt_log_level = CORE_LOG_BT_LOG_LEVEL_OFF;
64+
}
65+
66+
void core_log_bt_level_set(enum core_log_bt_log_level level)
67+
{
68+
_core_log_bt_log_level = level;
69+
}
70+
71+
void core_log_bt_fini()
72+
{
73+
log_assert(_core_log_bt_sink);
74+
75+
_core_log_bt_sink->close(_core_log_bt_sink->ctx);
76+
77+
free(_core_log_bt_sink);
78+
}
79+
80+
void core_log_bt_log_fatal(const char *module, const char *fmt, ...)
81+
{
82+
va_list ap;
83+
84+
if (_core_log_bt_log_level >= CORE_LOG_BT_LOG_LEVEL_FATAL) {
85+
va_start(ap, fmt);
86+
_core_log_bt_vformat_write(
87+
CORE_LOG_BT_LOG_LEVEL_FATAL, module, fmt, ap);
88+
va_end(ap);
89+
}
90+
}
91+
92+
void core_log_bt_log_warning(const char *module, const char *fmt, ...)
93+
{
94+
va_list ap;
95+
96+
if (_core_log_bt_log_level >= CORE_LOG_BT_LOG_LEVEL_WARNING) {
97+
va_start(ap, fmt);
98+
_core_log_bt_vformat_write(
99+
CORE_LOG_BT_LOG_LEVEL_WARNING, module, fmt, ap);
100+
va_end(ap);
101+
}
102+
}
103+
104+
void core_log_bt_log_info(const char *module, const char *fmt, ...)
105+
{
106+
va_list ap;
107+
108+
if (_core_log_bt_log_level >= CORE_LOG_BT_LOG_LEVEL_INFO) {
109+
va_start(ap, fmt);
110+
_core_log_bt_vformat_write(CORE_LOG_BT_LOG_LEVEL_INFO, module, fmt, ap);
111+
va_end(ap);
112+
}
113+
}
114+
115+
void core_log_bt_log_misc(const char *module, const char *fmt, ...)
116+
{
117+
va_list ap;
118+
119+
if (_core_log_bt_log_level >= CORE_LOG_BT_LOG_LEVEL_MISC) {
120+
va_start(ap, fmt);
121+
_core_log_bt_vformat_write(CORE_LOG_BT_LOG_LEVEL_MISC, module, fmt, ap);
122+
va_end(ap);
123+
}
124+
}
125+
126+
void core_log_bt_direct_sink_write(const char *chars, size_t nchars)
127+
{
128+
_core_log_bt_sink->write(_core_log_bt_sink->ctx, chars, nchars);
129+
}

‎src/main/core/log-bt.h‎

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
#ifndef CORE_LOG_BT_H
2+
#define CORE_LOG_BT_H
3+
4+
#include "core/log-sink.h"
5+
6+
/**
7+
* Log API implementation for games/applications without AVS
8+
*/
9+
10+
enum core_log_bt_log_level {
11+
CORE_LOG_BT_LOG_LEVEL_OFF = 0,
12+
CORE_LOG_BT_LOG_LEVEL_FATAL = 1,
13+
CORE_LOG_BT_LOG_LEVEL_WARNING = 2,
14+
CORE_LOG_BT_LOG_LEVEL_INFO = 3,
15+
CORE_LOG_BT_LOG_LEVEL_MISC = 4,
16+
};
17+
18+
/**
19+
* Initialize the logging backend
20+
*
21+
* This must be called as early as possible in your application to setup
22+
* a logging sink according to your needs. Until this is finished, no
23+
* log output is available.
24+
*
25+
* By default, logging is turned off entirely and must be enabled by setting
26+
* a desired logging level explicitly.
27+
*
28+
* @param sink Pointer to a log sink implementation. The caller owns the memory
29+
* of this.
30+
*/
31+
void core_log_bt_init(const struct core_log_sink *sink);
32+
33+
/**
34+
* Set the current logging level. This can be changed at any given time, e.g.
35+
* to increase/decrease verbosity.
36+
*
37+
* @param level The logging level to set.
38+
*/
39+
void core_log_bt_level_set(enum core_log_bt_log_level level);
40+
41+
/**
42+
* Cleanup the logging backend.
43+
*
44+
* Ensure to call this on application exit and cleanup.
45+
*/
46+
void core_log_bt_fini();
47+
48+
/**
49+
* Implementation of the log API.
50+
*/
51+
void core_log_bt_log_fatal(const char *module, const char *fmt, ...);
52+
53+
/**
54+
* Implementation of the log API.
55+
*/
56+
void core_log_bt_log_warning(const char *module, const char *fmt, ...);
57+
58+
/**
59+
* Implementation of the log API.
60+
*/
61+
void core_log_bt_log_info(const char *module, const char *fmt, ...);
62+
63+
/**
64+
* Implementation of the log API.
65+
*/
66+
void core_log_bt_log_misc(const char *module, const char *fmt, ...);
67+
68+
/**
69+
* Allow AVS to by-pass the core log API/engine.
70+
*
71+
* This function must only be called by AVS in an appropriate log callback
72+
* function that is passed to avs_boot.
73+
*
74+
* AVS has it's own logging engine and manages aspects such as async logging,
75+
* log levels and decorating log messages.
76+
*
77+
* Thus, proper interoperability only requires the writer/sink part to be shared
78+
* with AVS.
79+
*
80+
* @param chars Buffer with text data to write to the configured sinks. The
81+
* buffer might contain several log messages separated by newline
82+
* characters.
83+
* @param nchars Number of chars to write to the sink.
84+
*/
85+
void core_log_bt_direct_sink_write(const char *chars, size_t nchars);
86+
87+
#endif

0 commit comments

Comments
 (0)