Added threaded extools logging as an alternative to rust_g logging.

This commit is contained in:
Putnam
2020-08-31 19:56:49 -07:00
parent 5bcae6431b
commit 2f3edb4491
8 changed files with 107 additions and 3 deletions
+1
View File
@@ -0,0 +1 @@
#define EXTOOLS (world.system_type == MS_WINDOWS ? "byond-extools.dll" : "libbyond-extools.so")
-2
View File
@@ -281,8 +281,6 @@ GLOBAL_LIST_INIT(atmos_adjacent_savings, list(0,0))
#define CALCULATE_ADJACENT_TURFS(T) SSadjacent_air.queue[T] = 1
#endif
#define EXTOOLS (world.system_type == MS_WINDOWS ? "byond-extools.dll" : "libbyond-extools.so")
GLOBAL_VAR(atmos_extools_initialized) // this must be an uninitialized (null) one or init_monstermos will be called twice because reasons
#define ATMOS_EXTOOLS_CHECK if(!GLOB.atmos_extools_initialized){\
GLOB.atmos_extools_initialized=TRUE;\
+89
View File
@@ -0,0 +1,89 @@
/*
TFFI - Threaded FFI
All DLL calls are automatically threaded off.
Black magic is used to suspend (sleep) the currently executing proc, allowing non-blocking FFI.
You may call a DLL function and sleep until it returns, pass a callback to be called with the result,
or call resolve() on the /datum/promise to receive the return value at any time.
Example:
var/x = call_wait("sample.dll", "do_work", "arg1", "arg2", "arg3")
- Calls the do_work function from sample.dll with 3 arguments. The proc sleeps until do_work returns.
var/datum/promise/P = call_async("sample.dll", "do_work", "arg1")
... do something else ...
var/result = P.resolve()
- Calls do_work with 1 argument. Returns a promise object. Runs some other code before calling P.resolve() to obtain the result.
/proc/print_result(result)
world << result
call_cb("sample.dll", "do_work", /proc/print_result, "arg1", "arg2")
- Calls do_work with 2 arguments. The callback is invoked with the result as the single argument. Execution resumes immediately.
*/
/proc/tffi_initialize()
return call(EXTOOLS, "tffi_initialize")()
var/fallback_alerted = FALSE
var/next_promise_id = 0
/datum/promise
var/completed = FALSE
var/result = ""
var/callback_context = GLOBAL_PROC
var/callback_proc = null
var/__id = 0
/datum/promise/New()
__id = next_promise_id++ //please don't create more than 10^38 promises in a single tick
//This proc's bytecode is overwritten to allow suspending and resuming on demand.
//None of the code here should run.
/datum/promise/proc/__internal_resolve(ref, id)
if(!fallback_alerted && world.system_type != UNIX) // the rewriting is currently broken on Linux.
world << "<b>TFFI: __internal_resolve has not been rewritten, the TFFI DLL was not loaded correctly.</b>"
world.log << "<b>TFFI: __internal_resolve has not been rewritten, the TFFI DLL was not loaded correctly.</b>"
fallback_alerted = TRUE
while(!completed)
sleep(1)
//It might be better to just fail and notify the user that something went wrong.
/datum/promise/proc/__resolve_callback()
__internal_resolve("\ref[src]", __id)
if(callback_context == GLOBAL_PROC)
call(callback_proc)(result)
else
call(callback_context, callback_proc)(result)
/datum/promise/proc/resolve()
__internal_resolve("\ref[src]", __id)
return result
/proc/call_async()
var/list/arguments = args.Copy()
var/datum/promise/P = new
arguments.Insert(1, "\ref[P]")
call(EXTOOLS, "call_async")(arglist(arguments))
return P
/proc/call_cb()
var/list/arguments = args.Copy()
var/context = arguments[3]
var/callback = arguments[4]
arguments.Cut(3, 5)
var/datum/promise/P = new
P.callback_context = context
P.callback_proc = callback
arguments.Insert(1, "\ref[P]")
call(EXTOOLS, "call_async")(arglist(arguments))
spawn(0)
P.__resolve_callback()
/proc/call_wait()
return call_async(arglist(args)).resolve()
/*
Logging -- same exact interface as rust_g logging, but threaded and doesn't go through call()().
*/
#define EXTOOLS_LOGGING // rust_g is used as a fallback if this is undefined
/proc/extools_log_write()
/proc/extools_finalize_logging()
+10 -1
View File
@@ -4,10 +4,15 @@
#define SEND_SOUND(target, sound) DIRECT_OUTPUT(target, sound)
#define SEND_TEXT(target, text) DIRECT_OUTPUT(target, text)
#define WRITE_FILE(file, text) DIRECT_OUTPUT(file, text)
#ifdef EXTOOLS_LOGGING
// proc hooked, so we can just put in standard TRUE and FALSE
#define WRITE_LOG(log, text) extools_log_write(log,text,TRUE)
#define WRITE_LOG_NO_FORMAT(log, text) extools_log_write(log,text,FALSE)
#else
//This is an external call, "true" and "false" are how rust parses out booleans
#define WRITE_LOG(log, text) rustg_log_write(log, text, "true")
#define WRITE_LOG_NO_FORMAT(log, text) rustg_log_write(log, text, "false")
#endif
//print a warning message to world.log
#define WARNING(MSG) warning("[MSG] in [__FILE__] at line [__LINE__] src: [UNLINT(src)] usr: [usr].")
/proc/warning(msg)
@@ -216,7 +221,11 @@
/* Close open log handles. This should be called as late as possible, and no logging should hapen after. */
/proc/shutdown_logging()
#ifdef EXTOOLS_LOGGING
extools_finalize_logging()
#else
rustg_log_close_all()
#endif
/* Helper procs for building detailed log lines */
+5
View File
@@ -11,6 +11,11 @@ GLOBAL_LIST(topic_status_cache)
/world/New()
if (fexists(EXTOOLS))
call(EXTOOLS, "maptick_initialize")()
#ifdef EXTOOLS_LOGGING
call(EXTOOLS, "init_logging")()
else
CRASH("[EXTOOLS] does not exist!")
#endif
enable_debugger()
#ifdef REFERENCE_TRACKING
enable_reference_tracking()