Compare commits

..

2 Commits
pr291 ... pr286

Author SHA1 Message Date
icex2
5833197b03 fix(hook): Add missing hook_table_revert impl
Allow hooks to cleanup when they are shut down.
2024-02-25 09:09:12 +01:00
icex2
7ee9a2e219 fix(dist): Incorrect versioning for ddr distribution packages
Apparently forgotten to get updated to reflect the
currently supported versions correctly.
2024-02-25 08:52:00 +01:00
54 changed files with 11 additions and 1710 deletions

View File

@@ -1,21 +0,0 @@
FROM --platform=amd64 debian:11.6-slim@sha256:f7d141c1ec6af549958a7a2543365a7829c2cdc4476308ec2e182f8a7c59b519
LABEL description="Development environment for bemanitools"
# mingw-w64-gcc has 32-bit and 64-bit toolchains
RUN apt-get update && apt-get install -y --no-install-recommends \
mingw-w64 \
mingw-w64-common \
make \
zip \
git \
clang-format \
python3-pip \
&& rm -rf /var/lib/apt/lists/*
RUN pip3 install mdformat
RUN mkdir /bemanitools
WORKDIR /bemanitools
ENV SHELL /bin/bash

View File

@@ -13,10 +13,8 @@ BUILDDIR ?= build
builddir_docker := $(BUILDDIR)/docker
docker_build_container_name := "bemanitools-build"
docker_build_image_name := "bemanitools-build:latest"
docker_dev_container_name := "bemanitools-dev"
docker_dev_image_name := "bemanitools-dev:latest"
docker_container_name := "bemanitools-build"
docker_image_name := "bemanitools-build:latest"
depdir := $(BUILDDIR)/dep
objdir := $(BUILDDIR)/obj
@@ -43,7 +41,6 @@ FORCE:
.PHONY: \
build-docker \
dev-docker \
clean \
code-format \
doc-format \
@@ -92,38 +89,21 @@ version:
$(V)echo "$(gitrev)" > version
build-docker:
$(V)docker rm -f $(docker_build_container_name) 2> /dev/null || true
$(V)docker rm -f $(docker_container_name) 2> /dev/null || true
$(V)docker \
build \
-t $(docker_build_image_name) \
-f Dockerfile.build \
-t $(docker_image_name) \
-f Dockerfile \
.
$(V)docker \
run \
--volume $(shell pwd):/bemanitools \
--name $(docker_build_container_name) \
$(docker_build_image_name)
dev-docker:
$(V)docker rm -f $(docker_dev_container_name) 2> /dev/null || true
$(V)docker \
build \
-t $(docker_dev_image_name) \
-f Dockerfile.dev \
.
$(V)docker \
run \
--interactive \
--tty \
--volume $(shell pwd):/bemanitools \
--name $(docker_dev_container_name) \
$(docker_dev_image_name)
--name $(docker_container_name) \
$(docker_image_name)
clean-docker:
$(V)docker rm -f $(docker_dev_container_name) || true
$(V)docker image rm -f $(docker_dev_image_name) || true
$(V)docker rm -f $(docker_build_container_name) || true
$(V)docker image rm -f $(docker_build_image_name) || true
$(V)docker rm -f $(docker_container_name) || true
$(V)docker image rm -f $(docker_image_name) || true
$(V)rm -rf $(BUILDDIR)
#

View File

@@ -100,7 +100,6 @@ include src/main/bstio/Module.mk
include src/main/camhook/Module.mk
include src/main/cconfig/Module.mk
include src/main/config/Module.mk
include src/main/core/Module.mk
include src/main/d3d9-util/Module.mk
include src/main/d3d9exhook/Module.mk
include src/main/ddrhook-util/Module.mk

View File

@@ -220,9 +220,6 @@ void property_file_write(struct property *prop, const char *path);
int property_set_flag(struct property *prop, int flags, int mask);
void property_destroy(struct property *prop);
avs_error property_get_error(struct property *prop);
void property_clear_error(struct property *prop);
int property_psmap_import(
struct property *prop,
struct property_node *root,

View File

@@ -25,8 +25,6 @@ EXPORTS
property_destroy
property_file_write
property_insert_read
property_clear_error
property_get_error
property_mem_write
property_read_query_memsize
property_search

View File

@@ -28,8 +28,6 @@ EXPORTS
property_destroy
property_file_write
property_insert_read
property_clear_error
property_get_error
property_mem_write
property_read_query_memsize
property_search

View File

@@ -26,8 +26,6 @@ EXPORTS
property_desc_to_buffer @246 NONAME
property_destroy @247 NONAME
property_insert_read @255 NONAME
property_clear_error @573 NONAME
property_get_error @573 NONAME
property_node_create @266 NONAME
property_node_datasize @267 NONAME
property_node_name @274 NONAME

View File

@@ -25,8 +25,6 @@ EXPORTS
property_desc_to_buffer @201 NONAME
property_destroy @264 NONAME
property_insert_read @23 NONAME
property_clear_error @573 NONAME
property_get_error @573 NONAME
property_node_create @316 NONAME
property_node_datasize @249 NONAME
property_node_name @255 NONAME

View File

@@ -25,8 +25,6 @@ EXPORTS
property_desc_to_buffer @201 NONAME == XC058ba50000cd
property_destroy @264 NONAME == XC058ba500010f
property_insert_read @23 NONAME == XC058ba5000016
property_clear_error @573 NONAME
property_get_error @573 NONAME
property_node_create @316 NONAME == XC058ba5000143
property_node_datasize @249 NONAME == XC058ba5000100
property_node_name @255 NONAME == XC058ba5000106

View File

@@ -24,8 +24,6 @@ EXPORTS
property_desc_to_buffer @131 NONAME
property_destroy @130 NONAME
property_insert_read @133 NONAME
property_clear_error @573 NONAME
property_get_error @573 NONAME
property_node_name @573 NONAME ==
property_node_read @573 NONAME ==
property_node_remove @148 NONAME

View File

@@ -26,8 +26,6 @@ EXPORTS
property_desc_to_buffer @129 NONAME
property_destroy @128 NONAME
property_insert_read @131 NONAME
property_clear_error @573 NONAME
property_get_error @573 NONAME
property_node_create @145 NONAME
property_node_name @150 NONAME
property_node_read @154 NONAME == XCd229cc0000f3

View File

@@ -19,8 +19,6 @@ EXPORTS
property_destroy @125 NONAME
property_desc_to_buffer @126 NONAME
property_insert_read @128 NONAME
property_clear_error @573 NONAME
property_get_error @573 NONAME
property_search @141 NONAME
property_node_create @142 NONAME
property_node_name @147 NONAME == XCnbrep7000092

View File

@@ -19,8 +19,6 @@ EXPORTS
property_destroy @146 NONAME
property_desc_to_buffer @147 NONAME
property_insert_read @149 NONAME
property_clear_error @158 NONAME == XCnbrep700009d
property_get_error @159 NONAME == XCnbrep700009e
property_search @162 NONAME
property_node_create @163 NONAME
property_node_name @168 NONAME == XCnbrep70000a7

View File

@@ -21,8 +21,6 @@ EXPORTS
property_destroy @146 NONAME
property_desc_to_buffer @147 NONAME
property_insert_read @149 NONAME
property_clear_error @158 NONAME == XCgsqzn000009d
property_get_error @159 NONAME == XCgsqzn000009e
property_search @162 NONAME
property_node_create @163 NONAME
property_node_name @168 NONAME == XCgsqzn00000a7

View File

@@ -25,8 +25,6 @@ EXPORTS
property_destroy
property_file_write
property_insert_read
property_clear_error
property_get_error
property_mem_write
property_read_query_memsize
property_search

View File

@@ -26,8 +26,6 @@ EXPORTS
property_desc_to_buffer @129 NONAME
property_destroy @128 NONAME
property_insert_read @131 NONAME
property_clear_error @573 NONAME
property_get_error @573 NONAME
property_node_create @145 NONAME
property_node_name @150 NONAME
property_node_read @154 NONAME == XCd229cc0000f3

View File

@@ -26,8 +26,6 @@ EXPORTS
property_desc_to_buffer @129 NONAME
property_destroy @128 NONAME
property_insert_read @131 NONAME
property_clear_error @573 NONAME
property_get_error @573 NONAME
property_node_create @145 NONAME
property_node_name @573 NONAME ==
property_node_read @573 NONAME ==

View File

@@ -19,8 +19,6 @@ EXPORTS
property_destroy @125 NONAME
property_desc_to_buffer @126 NONAME
property_insert_read @128 NONAME
property_clear_error @573 NONAME
property_get_error @573 NONAME
property_search @141 NONAME
property_node_create @142 NONAME
property_node_name @147 NONAME == XCnbrep7000092

View File

@@ -19,14 +19,12 @@ EXPORTS
property_destroy @146 NONAME
property_desc_to_buffer @147 NONAME
property_insert_read @149 NONAME
property_clear_error @158 NONAME == XCnbrep700009d
property_get_error @159 NONAME == XCnbrep700009e
property_search @162 NONAME
property_node_create @163 NONAME
property_node_name @168 NONAME == XCnbrep70000a7
property_node_remove @164 NONAME
property_node_type @169 NONAME == XCnbrep70000a8
property_node_clone @165 NONAME == XCnbrep70000a4
property_node_clone @165 NONAME
property_node_traversal @167 NONAME
property_node_refdata @166 NONAME == XCnbrep70000a5
property_node_datasize @171 NONAME == XCnbrep70000aa

View File

@@ -21,8 +21,6 @@ EXPORTS
property_destroy @146 NONAME
property_desc_to_buffer @147 NONAME
property_insert_read @149 NONAME
property_clear_error @158 NONAME == XCgsqzn000009d
property_get_error @159 NONAME == XCgsqzn000009e
property_search @162 NONAME
property_node_create @163 NONAME
property_node_name @168 NONAME == XCgsqzn00000a7

View File

@@ -3,5 +3,4 @@ libs += avs-util
libs_avs-util := \
src_avs-util := \
core-interop.c \
error.c \

View File

@@ -1,16 +0,0 @@
#include "core/log.h"
#include "core/thread.h"
#include "imports/avs.h"
void avs_util_core_interop_log_avs_impl_set()
{
core_log_impl_set(
log_body_misc, log_body_info, log_body_warning, log_body_fatal);
}
void avs_util_core_interop_thread_avs_impl_set()
{
core_thread_impl_set(
avs_thread_create, avs_thread_join, avs_thread_destroy);
}

View File

@@ -1,7 +0,0 @@
#ifndef AVS_UTIL_CORE_INTEROP_H
#define AVS_UTIL_CORE_INTEROP_H
void avs_util_core_interop_log_avs_impl_set();
void avs_util_core_interop_thread_avs_impl_set();
#endif

View File

@@ -96,14 +96,4 @@ const char *avs_util_error_str(avs_error error)
}
return avs_util_error_unknown;
}
const char *avs_util_property_error_get_and_clear(struct property *prop)
{
avs_error error;
error = property_get_error(prop);
property_clear_error(prop);
return avs_util_error_str(error);
}

View File

@@ -5,6 +5,4 @@
const char *avs_util_error_str(avs_error error);
const char *avs_util_property_error_get_and_clear(struct property *prop);
#endif
#endif

View File

@@ -1,20 +0,0 @@
libs += core
libs_core := \
util \
src_core := \
log-bt-ext.c \
log-bt.c \
log-sink-async.c \
log-sink-debug.c \
log-sink-file.c \
log-sink-list.c \
log-sink-mutex.c \
log-sink-null.c \
log-sink-std.c \
log.c \
thread-crt-ext.c \
thread-crt.c \
thread.c \

View File

@@ -1,67 +0,0 @@
#include <stdbool.h>
#include "core/log-bt.h"
#include "core/log-sink-debug.h"
#include "core/log-sink-file.h"
#include "core/log-sink-list.h"
#include "core/log-sink-mutex.h"
#include "core/log-sink-std.h"
#include "core/log.h"
void core_log_bt_ext_impl_set()
{
core_log_impl_set(
core_log_bt_log_misc,
core_log_bt_log_info,
core_log_bt_log_warning,
core_log_bt_log_fatal);
}
void core_log_bt_ext_init_with_stdout()
{
struct core_log_sink sink;
core_log_sink_std_out_open(true, &sink);
core_log_bt_init(&sink);
}
void core_log_bt_ext_init_with_stderr()
{
struct core_log_sink sink;
core_log_sink_std_err_open(true, &sink);
core_log_bt_init(&sink);
}
void core_log_bt_ext_init_with_debug()
{
struct core_log_sink sink;
core_log_sink_debug_open(&sink);
core_log_bt_init(&sink);
}
void core_log_bt_ext_init_with_file(
const char *path, bool append, bool rotate, uint8_t max_rotations)
{
struct core_log_sink sink;
core_log_sink_file_open(path, append, rotate, max_rotations, &sink);
core_log_bt_init(&sink);
}
void core_log_bt_ext_init_with_stdout_and_file(
const char *path, bool append, bool rotate, uint8_t max_rotations)
{
struct core_log_sink sinks[2];
struct core_log_sink sink_composed;
struct core_log_sink sink_mutex;
core_log_sink_std_out_open(true, &sinks[0]);
core_log_sink_file_open(path, append, rotate, max_rotations, &sinks[1]);
core_log_sink_list_open(sinks, 2, &sink_composed);
core_log_sink_mutex_open(&sink_composed, &sink_mutex);
core_log_bt_init(&sink_mutex);
}

View File

@@ -1,59 +0,0 @@
#ifndef CORE_LOG_BT_EXT_H
#define CORE_LOG_BT_EXT_H
#include <stdbool.h>
#include <stdint.h>
/**
* Set the current thread API implementation to use the bemanitools log
* implementation
*/
void core_log_bt_ext_impl_set();
/**
* Helper to setup the bemanitools log implementation with a stdout sink.
*/
void core_log_bt_ext_init_with_stdout();
/**
* Helper to setup the bemanitools log implementation with a stderr sink.
*/
void core_log_bt_ext_init_with_stderr();
/**
* Helper to setup the bemanitools log implementation with a OutputDebugStr
* sink.
*/
void core_log_bt_ext_init_with_debug();
/**
* Helper to setup the bemanitools log implementation with a file sink
*
* @param path Path to the log file to write the log output to
* @param append If true, then append to an existing file, false to overwrite
* any existing file
* @param rotate If true, rotates an existing log file and creates a new one
* for this session
* @param max_rotations Max number of rotations for the log files
*/
void core_log_bt_ext_init_with_file(
const char *path, bool append, bool rotate, uint8_t max_rotations);
/**
* Helper to setup the bemanitools log implementation with a stdout and file
* sink
*
* Important: This combined sink is guarded by a mutex to avoid data races on
* logging to two different sinks.
*
* @param path Path to the log file to write the log output to
* @param append If true, then append to an existing file, false to overwrite
* any existing file
* @param rotate If true, rotates an existing log file and creates a new one
* for this session
* @param max_rotations Max number of rotations for the log files
*/
void core_log_bt_ext_init_with_stdout_and_file(
const char *path, bool append, bool rotate, uint8_t max_rotations);
#endif

View File

@@ -1,129 +0,0 @@
#include <stdarg.h>
#include <stdlib.h>
#include <time.h>
#include "core/log-bt.h"
#include "core/log-sink.h"
#include "core/log.h"
#include "util/mem.h"
#include "util/str.h"
static enum core_log_bt_log_level _core_log_bt_log_level;
static struct core_log_sink *_core_log_bt_sink;
static void _core_log_bt_vformat_write(
enum core_log_bt_log_level level,
const char *module,
const char *fmt,
va_list ap)
{
static const char chars[] = "FFWIM";
char timestamp[64];
/* 64k so we can log data dumps of rs232 without crashing */
char msg[65536];
char line[65536];
int result;
time_t curtime;
struct tm *tm;
curtime = 0;
tm = NULL;
curtime = time(NULL);
tm = localtime(&curtime);
strftime(timestamp, sizeof(timestamp), "[%Y/%m/%d %H:%M:%S]", tm);
str_vformat(msg, sizeof(msg), fmt, ap);
result = str_format(
line,
sizeof(line),
"%s %c:%s: %s\n",
timestamp,
chars[level],
module,
msg);
_core_log_bt_sink->write(_core_log_bt_sink->ctx, line, result);
}
void core_log_bt_init(const struct core_log_sink *sink)
{
if (sink == NULL) {
abort();
}
_core_log_bt_sink = xmalloc(sizeof(struct core_log_sink));
memcpy(_core_log_bt_sink, sink, sizeof(struct core_log_sink));
_core_log_bt_log_level = CORE_LOG_BT_LOG_LEVEL_OFF;
}
void core_log_bt_level_set(enum core_log_bt_log_level level)
{
_core_log_bt_log_level = level;
}
void core_log_bt_fini()
{
log_assert(_core_log_bt_sink);
_core_log_bt_sink->close(_core_log_bt_sink->ctx);
free(_core_log_bt_sink);
}
void core_log_bt_log_fatal(const char *module, const char *fmt, ...)
{
va_list ap;
if (_core_log_bt_log_level >= CORE_LOG_BT_LOG_LEVEL_FATAL) {
va_start(ap, fmt);
_core_log_bt_vformat_write(
CORE_LOG_BT_LOG_LEVEL_FATAL, module, fmt, ap);
va_end(ap);
}
}
void core_log_bt_log_warning(const char *module, const char *fmt, ...)
{
va_list ap;
if (_core_log_bt_log_level >= CORE_LOG_BT_LOG_LEVEL_WARNING) {
va_start(ap, fmt);
_core_log_bt_vformat_write(
CORE_LOG_BT_LOG_LEVEL_WARNING, module, fmt, ap);
va_end(ap);
}
}
void core_log_bt_log_info(const char *module, const char *fmt, ...)
{
va_list ap;
if (_core_log_bt_log_level >= CORE_LOG_BT_LOG_LEVEL_INFO) {
va_start(ap, fmt);
_core_log_bt_vformat_write(CORE_LOG_BT_LOG_LEVEL_INFO, module, fmt, ap);
va_end(ap);
}
}
void core_log_bt_log_misc(const char *module, const char *fmt, ...)
{
va_list ap;
if (_core_log_bt_log_level >= CORE_LOG_BT_LOG_LEVEL_MISC) {
va_start(ap, fmt);
_core_log_bt_vformat_write(CORE_LOG_BT_LOG_LEVEL_MISC, module, fmt, ap);
va_end(ap);
}
}
void core_log_bt_direct_sink_write(const char *chars, size_t nchars)
{
_core_log_bt_sink->write(_core_log_bt_sink->ctx, chars, nchars);
}

View File

@@ -1,87 +0,0 @@
#ifndef CORE_LOG_BT_H
#define CORE_LOG_BT_H
#include "core/log-sink.h"
/**
* Log API implementation for games/applications without AVS
*/
enum core_log_bt_log_level {
CORE_LOG_BT_LOG_LEVEL_OFF = 0,
CORE_LOG_BT_LOG_LEVEL_FATAL = 1,
CORE_LOG_BT_LOG_LEVEL_WARNING = 2,
CORE_LOG_BT_LOG_LEVEL_INFO = 3,
CORE_LOG_BT_LOG_LEVEL_MISC = 4,
};
/**
* Initialize the logging backend
*
* This must be called as early as possible in your application to setup
* a logging sink according to your needs. Until this is finished, no
* log output is available.
*
* By default, logging is turned off entirely and must be enabled by setting
* a desired logging level explicitly.
*
* @param sink Pointer to a log sink implementation. The caller owns the memory
* of this.
*/
void core_log_bt_init(const struct core_log_sink *sink);
/**
* Set the current logging level. This can be changed at any given time, e.g.
* to increase/decrease verbosity.
*
* @param level The logging level to set.
*/
void core_log_bt_level_set(enum core_log_bt_log_level level);
/**
* Cleanup the logging backend.
*
* Ensure to call this on application exit and cleanup.
*/
void core_log_bt_fini();
/**
* Implementation of the log API.
*/
void core_log_bt_log_fatal(const char *module, const char *fmt, ...);
/**
* Implementation of the log API.
*/
void core_log_bt_log_warning(const char *module, const char *fmt, ...);
/**
* Implementation of the log API.
*/
void core_log_bt_log_info(const char *module, const char *fmt, ...);
/**
* Implementation of the log API.
*/
void core_log_bt_log_misc(const char *module, const char *fmt, ...);
/**
* Allow AVS to by-pass the core log API/engine.
*
* This function must only be called by AVS in an appropriate log callback
* function that is passed to avs_boot.
*
* AVS has it's own logging engine and manages aspects such as async logging,
* log levels and decorating log messages.
*
* Thus, proper interoperability only requires the writer/sink part to be shared
* with AVS.
*
* @param chars Buffer with text data to write to the configured sinks. The
* buffer might contain several log messages separated by newline
* characters.
* @param nchars Number of chars to write to the sink.
*/
void core_log_bt_direct_sink_write(const char *chars, size_t nchars);
#endif

View File

@@ -1,23 +0,0 @@
#include <stdlib.h>
#include "core/log-sink.h"
static void
_core_log_sink_file_write(void *ctx, const char *chars, size_t nchars)
{
// TODO
}
static void _core_log_sink_file_close(void *ctx)
{
// TODO
}
void core_log_sink_async_open(struct core_log_sink *sink)
{
// TODO
sink->ctx = NULL;
sink->write = _core_log_sink_file_write;
sink->close = _core_log_sink_file_close;
}

View File

@@ -1,19 +0,0 @@
#ifndef CORE_LOG_SINK_ASYNC_H
#define CORE_LOG_SINK_ASYNC_H
#include <stdint.h>
#include <stdlib.h>
#include "core/log-sink.h"
/**
* Open a async log sink
*
* The sink passes data to log to a separate thread which executes the actual
* logging of the data.
*
* @param sink Pointer to allocated memory that receives the opened sink
*/
void core_log_sink_async_open(struct core_log_sink *sink);
#endif

View File

@@ -1,23 +0,0 @@
#include <debugapi.h>
#include <stdlib.h>
#include "core/log-sink.h"
static void
_core_log_sink_debug_write(void *ctx, const char *chars, size_t nchars)
{
OutputDebugStringA(chars);
}
static void _core_log_sink_debug_close(void *ctx)
{
// noop
}
void core_log_sink_debug_open(struct core_log_sink *sink)
{
sink->ctx = NULL;
sink->write = _core_log_sink_debug_write;
sink->close = _core_log_sink_debug_close;
}

View File

@@ -1,15 +0,0 @@
#ifndef CORE_LOG_SINK_DEBUG_H
#define CORE_LOG_SINK_DEBUG_H
#include <stdlib.h>
#include "core/log-sink.h"
/**
* Open a log sink that uses OutputDebugStr
*
* @param sink Pointer to allocated memory that receives the opened sink
*/
void core_log_sink_debug_open(struct core_log_sink *sink);
#endif

View File

@@ -1,92 +0,0 @@
#include <windows.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include "core/log-sink.h"
#include "util/fs.h"
#include "util/str.h"
static void _core_log_sink_file_rotate(const char *path, uint8_t max_rotations)
{
uint8_t i;
char rotate_file[MAX_PATH];
char rotate_file_next[MAX_PATH];
char version[8];
char version_next[8];
for (i = max_rotations; i > 0; i++) {
str_cpy(rotate_file, sizeof(rotate_file), path);
str_cpy(rotate_file_next, sizeof(rotate_file_next), path);
if (i - 1 != 0) {
sprintf(version, ".%d", i);
} else {
memset(version, 0, sizeof(version));
}
sprintf(version_next, ".%d", i);
str_cat(rotate_file, sizeof(rotate_file), version);
str_cat(rotate_file_next, sizeof(rotate_file_next), version_next);
if (path_exists(rotate_file)) {
CopyFile(rotate_file, rotate_file_next, FALSE);
}
}
}
static void
_core_log_sink_file_write(void *ctx, const char *chars, size_t nchars)
{
FILE *file;
file = (FILE *) ctx;
fwrite(chars, 1, nchars, file);
}
static void _core_log_sink_file_close(void *ctx)
{
FILE *file;
file = (FILE *) ctx;
fflush(file);
fclose(file);
}
void core_log_sink_file_open(
const char *path,
bool append,
bool rotate,
uint8_t max_rotations,
struct core_log_sink *sink)
{
FILE *file;
if (rotate) {
_core_log_sink_file_rotate(path, max_rotations);
// Appending doesn't matter when file is rotated anyway
file = fopen(path, "w+");
} else {
if (append) {
file = fopen(path, "a+");
} else {
file = fopen(path, "w+");
}
}
if (!file) {
printf("Cannot open log file: %s", path);
abort();
}
sink->ctx = (void *) file;
sink->write = _core_log_sink_file_write;
sink->close = _core_log_sink_file_close;
}

View File

@@ -1,28 +0,0 @@
#ifndef CORE_LOG_SINK_FILE_H
#define CORE_LOG_SINK_FILE_H
#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h>
#include "core/log-sink.h"
/**
* Open a log sink writing data to a file
*
* @param path Path to the log file to write the log output to
* @param append If true, then append to an existing file, false to overwrite
* any existing file
* @param rotate If true, rotates an existing log file and creates a new one
* for this session
* @param max_rotations Max number of rotations for the log files
* @param sink Pointer to allocated memory that receives the opened sink
*/
void core_log_sink_file_open(
const char *path,
bool append,
bool rotate,
uint8_t max_rotations,
struct core_log_sink *sink);
#endif

View File

@@ -1,66 +0,0 @@
#include <stdint.h>
#include <stdlib.h>
#include "core/log-sink-list.h"
#include "core/log-sink.h"
#include "util/mem.h"
#define MAX_SINKS 8
struct core_log_sink_list {
struct core_log_sink entries[MAX_SINKS];
uint8_t num;
};
static void
_core_log_sink_list_write(void *ctx, const char *chars, size_t nchars)
{
struct core_log_sink_list *sink_list;
int i;
sink_list = (struct core_log_sink_list *) ctx;
for (i = 0; i < sink_list->num; i++) {
sink_list->entries[i].write(sink_list->entries[i].ctx, chars, nchars);
}
}
static void _core_log_sink_list_close(void *ctx)
{
struct core_log_sink_list *sink_list;
int i;
sink_list = (struct core_log_sink_list *) ctx;
for (i = 0; i < sink_list->num; i++) {
sink_list->entries[i].close(sink_list->entries[i].ctx);
}
free(sink_list);
}
void core_log_sink_list_open(
const struct core_log_sink *entry, uint8_t num, struct core_log_sink *sink)
{
struct core_log_sink_list *sink_list;
int i;
if (num > MAX_SINKS) {
abort();
}
sink_list = xmalloc(sizeof(struct core_log_sink_list));
for (i = 0; i < num; i++) {
sink_list->entries[i].ctx = entry[i].ctx;
sink_list->entries[i].write = entry[i].write;
sink_list->entries[i].close = entry[i].close;
}
sink_list->num = num;
sink->ctx = (void *) sink_list;
sink->write = _core_log_sink_list_write;
sink->close = _core_log_sink_list_close;
}

View File

@@ -1,24 +0,0 @@
#ifndef CORE_LOG_SINK_LIST_H
#define CORE_LOG_SINK_LIST_H
#include <stdint.h>
#include <stdlib.h>
#include "core/log-sink.h"
/**
* Combine multiple log sinks into a list of sinks.
*
* Upon invoking a list sink, all sinks contained within the list are
* being invoked in the configured order.
*
* @param entry A pointer to allocated memory with a sequence of opened sinks
* that you want to add to the list. Ownership of these sinks
* is transferred, i.e. closing the list sink closes its children.
* @param num The number of elements in the sequence of opened sinks pointed to.
* @param sink Pointer to allocated memory that receives the opened sink
*/
void core_log_sink_list_open(
const struct core_log_sink *entry, uint8_t num, struct core_log_sink *sink);
#endif

View File

@@ -1,53 +0,0 @@
#include <windows.h>
#include <stdlib.h>
#include "core/log-sink.h"
#include "util/mem.h"
struct core_log_sink_mutex_ctx {
struct core_log_sink *child;
HANDLE mutex;
};
static void
_core_log_sink_mutex_write(void *ctx_, const char *chars, size_t nchars)
{
struct core_log_sink_mutex_ctx *ctx;
ctx = (struct core_log_sink_mutex_ctx *) ctx_;
WaitForSingleObject(ctx->mutex, INFINITE);
ctx->child->write(ctx->child->ctx, chars, nchars);
ReleaseMutex(ctx->mutex);
}
static void _core_log_sink_mutex_close(void *ctx_)
{
struct core_log_sink_mutex_ctx *ctx;
ctx = (struct core_log_sink_mutex_ctx *) ctx_;
CloseHandle(ctx->mutex);
ctx->child->close(ctx->child->ctx);
free(ctx);
}
void core_log_sink_mutex_open(
const struct core_log_sink *child_sink, struct core_log_sink *sink)
{
struct core_log_sink_mutex_ctx *ctx;
ctx = xmalloc(sizeof(struct core_log_sink_mutex_ctx));
memcpy(ctx->child, child_sink, sizeof(struct core_log_sink));
ctx->mutex = CreateMutex(NULL, FALSE, NULL);
sink->ctx = ctx;
sink->write = _core_log_sink_mutex_write;
sink->close = _core_log_sink_mutex_close;
}

View File

@@ -1,21 +0,0 @@
#ifndef CORE_LOG_SINK_MUTEX_H
#define CORE_LOG_SINK_MUTEX_H
#include <stdlib.h>
#include "core/log-sink.h"
/**
* Create a sink that surrounds another sink with a mutex.
*
* Use this to make other sink implementations thread-safe.
*
* @param child_sink Another opened sink to surround with the mutex. Ownership
* of the sink is transferred, i.e. closing the mutex sink
* also closes the wrapped child sink.
* @param sink Pointer to allocated memory that receives the opened sink
*/
void core_log_sink_mutex_open(
const struct core_log_sink *child_sink, struct core_log_sink *sink);
#endif

View File

@@ -1,21 +0,0 @@
#include <stdlib.h>
#include "core/log-sink.h"
static void
_core_log_sink_null_write(void *ctx, const char *chars, size_t nchars)
{
// noop
}
static void _core_log_sink_null_close(void *ctx)
{
// noop
}
void core_log_sink_null_open(struct core_log_sink *sink)
{
sink->ctx = NULL;
sink->write = _core_log_sink_null_write;
sink->close = _core_log_sink_null_close;
}

View File

@@ -1,17 +0,0 @@
#ifndef CORE_LOG_SINK_NULL_H
#define CORE_LOG_SINK_NULL_H
#include <stdlib.h>
#include "core/log-sink.h"
/**
* Create a null/dummy sink.
*
* Use this to disable any logging entirely.
*
* @param sink Pointer to allocated memory that receives the opened sink
*/
void core_log_sink_null_open(struct core_log_sink *sink);
#endif

View File

@@ -1,193 +0,0 @@
#include <windows.h>
#include <stdlib.h>
#include "core/log-sink.h"
#include "util/mem.h"
struct core_log_sink_std_ctx {
HANDLE handle;
bool color;
};
static char _core_log_sink_std_determine_color(const char *str)
{
/* Add some color to make spotting warnings/errors easier.
Based on debug output level identifier. */
/* Avoids colored output on strings like "Windows" */
if (str[1] != ':') {
return 15;
}
switch (str[0]) {
/* green */
case 'M':
return 10;
/* blue */
case 'I':
return 9;
/* yellow */
case 'W':
return 14;
/* red */
case 'F':
return 12;
/* default console color */
default:
return 15;
}
}
static size_t _core_log_sink_std_msg_coloring_len(const char *str)
{
// Expected format example: "I:boot: my log message"
const char *ptr;
size_t len;
int colon_count;
ptr = str;
len = 0;
colon_count = 0;
while (true) {
// End of string = invalid log format
if (*ptr == '\0') {
return 0;
}
if (*ptr == ':') {
colon_count++;
}
if (colon_count == 2) {
// Skip current colon, next char is a space
return len + 1;
}
len++;
ptr++;
}
return 0;
}
static void
_core_log_sink_std_write(void *ctx_, const char *chars, size_t nchars)
{
static const size_t timestamp_len = strlen("[----/--/-- --:--:--]");
struct core_log_sink_std_ctx *ctx;
char color;
size_t color_len;
size_t msg_len;
const char *msg_start;
const char *msg_end;
DWORD written;
DWORD write_pos;
ctx = (struct core_log_sink_std_ctx *) ctx_;
if (ctx->color) {
write_pos = 0;
// Support multiple buffered log messages, e.g. from the AVS logging
// engine
while (write_pos < nchars) {
// Expects the AVS timestamp format
msg_start = chars + timestamp_len + 1; // +1 is the space
color_len = _core_log_sink_std_msg_coloring_len(msg_start);
// Check if we could detect which part to color, otherwise just
// write the whole log message without any coloring logic
if (color_len > 0) {
color = _core_log_sink_std_determine_color(msg_start);
// Timestamp
WriteConsole(
ctx->handle, chars, timestamp_len + 1, &written, NULL);
write_pos += written;
chars += written;
// Log level + module colored
SetConsoleTextAttribute(ctx->handle, color);
WriteConsole(ctx->handle, chars, color_len, &written, NULL);
write_pos += written;
chars += written;
SetConsoleTextAttribute(ctx->handle, 15);
msg_end = strchr(chars, '\n');
if (msg_end != NULL) {
msg_len = msg_end - chars;
// Write \n as well
msg_len++;
// Write actual message non colored
WriteConsole(ctx->handle, chars, msg_len, &written, NULL);
write_pos += written;
chars += written;
} else {
WriteConsole(
ctx->handle, chars, nchars - write_pos, &written, NULL);
write_pos += written;
chars += written;
}
} else {
WriteConsole(
ctx->handle,
chars + write_pos,
nchars - write_pos,
&written,
NULL);
write_pos += written;
}
}
} else {
WriteConsole(ctx->handle, chars, nchars, &written, NULL);
}
}
static void _core_log_sink_std_close(void *ctx_)
{
struct core_log_sink_std_ctx *ctx;
ctx = (struct core_log_sink_std_ctx *) ctx_;
// Remark: Don't close the ctx->handle, see win API docs
free(ctx);
}
void core_log_sink_std_out_open(bool color, struct core_log_sink *sink)
{
struct core_log_sink_std_ctx *ctx;
ctx = xmalloc(sizeof(struct core_log_sink_std_ctx));
ctx->handle = GetStdHandle(STD_OUTPUT_HANDLE);
ctx->color = color;
sink->ctx = (void *) ctx;
sink->write = _core_log_sink_std_write;
sink->close = _core_log_sink_std_close;
}
void core_log_sink_std_err_open(bool color, struct core_log_sink *sink)
{
struct core_log_sink_std_ctx *ctx;
ctx = xmalloc(sizeof(struct core_log_sink_std_ctx));
ctx->handle = GetStdHandle(STD_ERROR_HANDLE);
ctx->color = color;
sink->ctx = (void *) ctx;
sink->write = _core_log_sink_std_write;
sink->close = _core_log_sink_std_close;
}

View File

@@ -1,24 +0,0 @@
#ifndef CORE_LOG_SINK_STD_H
#define CORE_LOG_SINK_STD_H
#include <stdlib.h>
#include "core/log-sink.h"
/**
* Create a sink that writes to stdout.
*
* @param color If true, messages are colored by log level.
* @param sink Pointer to allocated memory that receives the opened sink
*/
void core_log_sink_std_out_open(bool color, struct core_log_sink *sink);
/**
* Create a sink that writes to stderr.
*
* @param color If true, messages are colored by log level.
* @param sink Pointer to allocated memory that receives the opened sink
*/
void core_log_sink_std_err_open(bool color, struct core_log_sink *sink);
#endif

View File

@@ -1,45 +0,0 @@
#ifndef CORE_LOG_SINK_H
#define CORE_LOG_SINK_H
#include <stdint.h>
/**
* Write function for a log sink implementation.
*
* Write the given data to your target output destination.
*
* @param ctx Context defined by the implementation when opening the sink.
* @param chars Buffer with text data to log. This can contain partial data of
* a single log line, a full log line terminated by a newline
* character or multiple log lines (each terminated by a newline
* character).
* @param nchars Number of characters to write.
*/
typedef void (*core_log_sink_write_t)(
void *ctx, const char *chars, size_t nchars);
/**
* Close your log sink and cleanup resources
*
* Depending on your implementation, you might want to flush any
* outstanding/buffered data.
*
* @param ctx Context defined by the implementation when opening the sink.
*/
typedef void (*core_log_sink_close_t)(void *ctx);
/**
* Log sink structure.
*
* This must be set-up and populated when opening your log sink implementation.
* The ctx field contains any arbitrary data that you need for your log sink
* to operate, e.g. a file handle, additional buffers etc. Make sure these
* resources are cleaned up upon closing the sink.
*/
struct core_log_sink {
void *ctx;
core_log_sink_write_t write;
core_log_sink_close_t close;
};
#endif

View File

@@ -1,74 +0,0 @@
#include <stdlib.h>
#include "core/log.h"
core_log_message_t _core_log_misc_impl;
core_log_message_t _core_log_info_impl;
core_log_message_t _core_log_warning_impl;
core_log_message_t _core_log_fatal_impl;
void core_log_impl_set(
core_log_message_t misc,
core_log_message_t info,
core_log_message_t warning,
core_log_message_t fatal)
{
if (misc == NULL || info == NULL || warning == NULL || fatal == NULL) {
abort();
}
_core_log_misc_impl = misc;
_core_log_info_impl = info;
_core_log_warning_impl = warning;
_core_log_fatal_impl = fatal;
}
void core_log_impl_assign(core_log_impl_set_t impl_set)
{
if (_core_log_misc_impl == NULL || _core_log_info_impl == NULL ||
_core_log_warning_impl == NULL || _core_log_fatal_impl == NULL) {
abort();
}
impl_set(
_core_log_misc_impl,
_core_log_info_impl,
_core_log_warning_impl,
_core_log_fatal_impl);
}
core_log_message_t core_log_misc_impl_get()
{
if (_core_log_misc_impl == NULL) {
abort();
}
return _core_log_misc_impl;
}
core_log_message_t core_log_info_impl_get()
{
if (_core_log_info_impl == NULL) {
abort();
}
return _core_log_info_impl;
}
core_log_message_t core_log_warning_impl_get()
{
if (_core_log_warning_impl == NULL) {
abort();
}
return _core_log_warning_impl;
}
core_log_message_t core_log_fatal_impl_get()
{
if (_core_log_fatal_impl == NULL) {
abort();
}
return _core_log_fatal_impl;
}

View File

@@ -1,197 +0,0 @@
#ifndef CORE_LOG_H
#define CORE_LOG_H
#include <stddef.h>
#include <stdlib.h>
#include "util/defs.h"
/**
* The core log API of bemanitools.
*
* To a large extent, this reflects the AVS logging API and allows for swapping
* out the backends with different implementations. Most games should have some
* version of the AVS API available while some (legacy) games do not. These
* can use a bemanitools private logging implementation by configuring it
* in the bootstrapping process.
*/
/* BUILD_MODULE is passed in as a command-line #define by the makefile */
#ifndef LOG_MODULE
#define LOG_MODULE STRINGIFY(BUILD_MODULE)
#endif
/**
* Log a message on misc level
*
* Always use this interface in your application which hides the currently
* configured implementation.
*
* The macro is required to make things work with varargs.
* The log message is only printed if the log level is set to misc
*
* @param fmt printf format string
* @param ... Additional arguments according to the specified arguments in the
* printf format string
*/
#define log_misc(...) _core_log_misc_impl(LOG_MODULE, __VA_ARGS__)
/**
* Log a message on info level
*
* Always use this interface in your application which hides the currently
* configured implementation.
*
* The macro is required to make things work with varargs.
* The log message is only printed if the log level is set to info or lower
*
* @param fmt printf format string
* @param ... Additional arguments according to the specified arguments in the
* printf format string
*/
#define log_info(...) _core_log_info_impl(LOG_MODULE, __VA_ARGS__)
/**
* Log a message on warning level
*
* Always use this interface in your application which hides the currently
* configured implementation.
*
* The macro is required to make things work with varargs.
* The log message is only printed if the log level is set to warning or lower
*
* @param fmt printf format string
* @param ... Additional arguments according to the specified arguments in the
* printf format string
*/
#define log_warning(...) _core_log_warning_impl(LOG_MODULE, __VA_ARGS__)
/**
* Log a message on fatal level
*
* Always use this interface in your application which hides the currently
* configured implementation.
*
* The macro is required to make things work with varargs.
* The log message is only printed if the log level is set to fatal.
*
* This call will also terminate the application.
*
* @param fmt printf format string
* @param ... Additional arguments according to the specified arguments in the
* printf format string
*/
#define log_fatal(...) \
do { \
_core_log_fatal_impl(LOG_MODULE, __VA_ARGS__); \
abort(); \
} while (0)
/**
* Log a message and terminate the application if given condition fails
*
* Always use this interface in your application which hides the currently
* configured implementation.
*
* The macro is required to make things work with varargs.
*
* @param x Condition to evaluate. If false, the application terminates
*/
#define log_assert(x) \
do { \
if (!(x)) { \
_core_log_fatal_impl( \
"assert", \
"%s:%d: function `%s'", \
__FILE__, \
__LINE__, \
__FUNCTION__); \
abort(); \
} \
} while (0)
/**
* Log a message in an exception handler
*
* Only use this function in an exception handler, e.g. for stack traces. It
* logs the message on fatal level but does not terminate.
*
* @param fmt printf format string
* @param ... Additional arguments according to the specified arguments in the
* printf format string
*/
#define log_exception_handler(...) \
_core_log_fatal_impl("exception", __VA_ARGS__)
typedef void (*core_log_message_t)(const char *module, const char *fmt, ...);
typedef void (*core_log_impl_set_t)(
core_log_message_t misc,
core_log_message_t info,
core_log_message_t warning,
core_log_message_t fatal);
/**
* Configure the log API implementations
*
* Advised to do this as early in your application/library module as possible
* as calls to the getter functions below will return the currently configured
* implementations.
*
* @param misc Pointer to a function implementing logging on misc level
* @param info Pointer to a function implementing logging on info level
* @param warning Pointer to a function implementing logging on warning level
* @param fatal Pointer to a function implementing logging on fatal level
*/
void core_log_impl_set(
core_log_message_t misc,
core_log_message_t info,
core_log_message_t warning,
core_log_message_t fatal);
/**
* Supporting function to inject/assign the currently set implementation
* with the given setter function.
*
* @param impl_set Setter function to call with the currently configured log
* function implementations
*/
void core_log_impl_assign(core_log_impl_set_t impl_set);
/**
* Get the currently configured implementation of the misc level log function
*
* @return Pointer to the currently configured implementation of the function
*/
core_log_message_t core_log_misc_impl_get();
/**
* Get the currently configured implementation of the info level log function
*
* @return Pointer to the currently configured implementation of the function
*/
core_log_message_t core_log_info_impl_get();
/**
* Get the currently configured implementation of the warning level log function
*
* @return Pointer to the currently configured implementation of the function
*/
core_log_message_t core_log_warning_impl_get();
/**
* Get the currently configured implementation of the fatal level log function
*
* @return Pointer to the currently configured implementation of the function
*/
core_log_message_t core_log_fatal_impl_get();
// Do not use these directly.
// These are only here to allow usage in the macros above.
extern core_log_message_t _core_log_misc_impl;
extern core_log_message_t _core_log_info_impl;
extern core_log_message_t _core_log_warning_impl;
extern core_log_message_t _core_log_fatal_impl;
#endif

View File

@@ -1,8 +0,0 @@
#include "core/thread-crt.h"
#include "core/thread.h"
void core_thread_crt_ext_impl_set()
{
core_thread_impl_set(
core_thread_crt_create, core_thread_crt_join, core_thread_crt_destroy);
}

View File

@@ -1,9 +0,0 @@
#ifndef CORE_THREAD_CRT_EXT_H
#define CORE_THREAD_CRT_EXT_H
/**
* Set the current thread API implementation to use the C runtime thread API
*/
void core_thread_crt_ext_impl_set();
#endif

View File

@@ -1,62 +0,0 @@
#include <process.h>
#include <windows.h>
#include <stddef.h>
#include <stdint.h>
#include "core/thread-crt.h"
#include "core/thread.h"
#include "util/defs.h"
struct shim_ctx {
HANDLE barrier;
int (*proc)(void *);
void *ctx;
};
static unsigned int STDCALL crt_thread_shim(void *outer_ctx)
{
struct shim_ctx *sctx = outer_ctx;
int (*proc)(void *);
void *inner_ctx;
proc = sctx->proc;
inner_ctx = sctx->ctx;
SetEvent(sctx->barrier);
return proc(inner_ctx);
}
int core_thread_crt_create(
int (*proc)(void *), void *ctx, uint32_t stack_sz, unsigned int priority)
{
struct shim_ctx sctx;
uintptr_t thread_id;
sctx.barrier = CreateEvent(NULL, TRUE, FALSE, NULL);
sctx.proc = proc;
sctx.ctx = ctx;
thread_id = _beginthreadex(NULL, stack_sz, crt_thread_shim, &sctx, 0, NULL);
WaitForSingleObject(sctx.barrier, INFINITE);
CloseHandle(sctx.barrier);
return (int) thread_id;
}
void core_thread_crt_destroy(int thread_id)
{
CloseHandle((HANDLE) (uintptr_t) thread_id);
}
void core_thread_crt_join(int thread_id, int *result)
{
WaitForSingleObject((HANDLE) (uintptr_t) thread_id, INFINITE);
if (result) {
GetExitCodeThread((HANDLE) (uintptr_t) thread_id, (DWORD *) result);
}
}

View File

@@ -1,15 +0,0 @@
#ifndef CORE_THREAD_CRT_H
#define CORE_THREAD_CRT_H
#include <stdint.h>
/**
* Thread API implementation using the C runtime API
*/
int core_thread_crt_create(
int (*proc)(void *), void *ctx, uint32_t stack_sz, unsigned int priority);
void core_thread_crt_join(int thread_id, int *result);
void core_thread_crt_destroy(int thread_id);
#endif

View File

@@ -1,78 +0,0 @@
#include <stdlib.h>
#include "core/log.h"
#include "core/thread.h"
core_thread_create_t core_thread_create_impl;
core_thread_join_t core_thread_join_impl;
core_thread_destroy_t core_thread_destroy_impl;
int core_thread_create(
int (*proc)(void *), void *ctx, uint32_t stack_sz, unsigned int priority)
{
log_assert(core_thread_create_impl);
return core_thread_create_impl(proc, ctx, stack_sz, priority);
}
void core_thread_join(int thread_id, int *result)
{
log_assert(core_thread_join_impl);
core_thread_join_impl(thread_id, result);
}
void core_thread_destroy(int thread_id)
{
log_assert(core_thread_destroy_impl);
core_thread_destroy_impl(thread_id);
}
void core_thread_impl_set(
core_thread_create_t create,
core_thread_join_t join,
core_thread_destroy_t destroy)
{
if (create == NULL || join == NULL || destroy == NULL) {
abort();
}
core_thread_create_impl = create;
core_thread_join_impl = join;
core_thread_destroy_impl = destroy;
}
void core_thread_impl_assign(core_thread_impl_set_t impl_set)
{
if (core_thread_create_impl == NULL || core_thread_join_impl == NULL ||
core_thread_destroy_impl == NULL) {
abort();
}
impl_set(
core_thread_create_impl,
core_thread_join_impl,
core_thread_destroy_impl);
}
core_thread_create_t core_thread_create_impl_get()
{
log_assert(core_thread_create_impl);
return core_thread_create_impl;
}
core_thread_join_t core_thread_join_impl_get()
{
log_assert(core_thread_join_impl);
return core_thread_join_impl;
}
core_thread_destroy_t core_thread_destroy_impl_get()
{
log_assert(core_thread_destroy_impl);
return core_thread_destroy_impl;
}

View File

@@ -1,117 +0,0 @@
#ifndef CORE_THREAD_H
#define CORE_THREAD_H
#include <stdint.h>
/**
* The core thread API of bemanitools.
*
* This essentially reflects the AVS threading API and allows for swapping out
* the backends with different implementations. Most games should have some
* version of the AVS API available while some (legacy) games do not. These
* can use a bemanitools private threading implementation by configuring it
* in the bootstrapping process.
*/
/**
* Create a thread
*
* Always use this interface in your application which hides the currently
* configured implementation.
*
* @param proc The function to run in a separate thread
* @param ctx Additional data to pass to the function as a parameter
* @param stack_sz The stack size to allocate for the thread in bytes
* @param priority The thread's priority
* @return The ID of the thread once created and started
*/
int core_thread_create(
int (*proc)(void *), void *ctx, uint32_t stack_sz, unsigned int priority);
/**
* Wait for a thread to finish
*
* Always use this interface in your application which hides the currently
* configured implementation.
*
* The caller of this function blocks until the thread has finished executing.
*
* @param thread_id ID of the thread to wait for
* @param result Pointer to a variable to write the return value of the function
* the thread executed to
*/
void core_thread_join(int thread_id, int *result);
/**
* Destroy a thread
*
* Always use this interface in your application which hides the currently
* configured implementation.
*
* The thread must have finished execution before calling this. It is advised
* to make threads terminate their execution flow, join them and destroy.
*
* @param thread_id The ID of the thread to destroy.
*/
void core_thread_destroy(int thread_id);
typedef int (*core_thread_create_t)(
int (*proc)(void *), void *ctx, uint32_t stack_sz, unsigned int priority);
typedef void (*core_thread_join_t)(int thread_id, int *result);
typedef void (*core_thread_destroy_t)(int thread_id);
typedef void (*core_thread_impl_set_t)(
core_thread_create_t create,
core_thread_join_t join,
core_thread_destroy_t destroy);
/**
* Configure the thread API implementations
*
* Advised to do this as early in your application/library module as possible
* as calls to the getter functions below will return the currently configured
* implementations.
*
* @param create Pointer to a function implementing thread creation
* @param join Pointer to a function implementing joining of a thread
* @param destroy Pointer to a function implementing destroying of a thread
*/
void core_thread_impl_set(
core_thread_create_t create,
core_thread_join_t join,
core_thread_destroy_t destroy);
/**
* Supporting function to inject/assign the currently set implementation
* with the given setter function.
*
* @param impl_set Setter function to call with the currently configured thread
* function implementations
*/
void core_thread_impl_assign(core_thread_impl_set_t impl_set);
/**
* Get the currently configured implementation for thread_create
*
* @return Pointer to the currently configured implementation of the
* thread_create function
*/
core_thread_create_t core_thread_create_impl_get();
/**
* Get the currently configured implementation for thread_join
*
* @return Pointer to the currently configured implementation of the thread_join
* function
*/
core_thread_join_t core_thread_join_impl_get();
/**
* Get the currently configured implementation for thread_destroy
*
* @return Pointer to the currently configured implementation of the
* thread_destroy function
*/
core_thread_destroy_t core_thread_destroy_impl_get();
#endif