remove script
Some checks failed
Build and Deploy / package-dist (push) Has been cancelled
Build and Deploy / deploy-itch (push) Has been cancelled
Build and Deploy / deploy-gitea (push) Has been cancelled
Build and Deploy / build-linux (push) Has been cancelled
Build and Deploy / build-windows (CLANG64) (push) Has been cancelled
Some checks failed
Build and Deploy / package-dist (push) Has been cancelled
Build and Deploy / deploy-itch (push) Has been cancelled
Build and Deploy / deploy-gitea (push) Has been cancelled
Build and Deploy / build-linux (push) Has been cancelled
Build and Deploy / build-windows (CLANG64) (push) Has been cancelled
This commit is contained in:
2
Makefile
2
Makefile
@@ -1,5 +1,5 @@
|
|||||||
debug: FORCE
|
debug: FORCE
|
||||||
meson setup build_dbg -Dbuildtype=debugoptimized
|
meson setup build_dbg -Dbuildtype=debug
|
||||||
meson compile -C build_dbg
|
meson compile -C build_dbg
|
||||||
|
|
||||||
fast: FORCE
|
fast: FORCE
|
||||||
|
|||||||
@@ -137,7 +137,7 @@ deps += dependency('soloud', static:true)
|
|||||||
deps += dependency('libqrencode', static: true)
|
deps += dependency('libqrencode', static: true)
|
||||||
|
|
||||||
sources = []
|
sources = []
|
||||||
src += ['anim.c', 'config.c', 'datastream.c','font.c','HandmadeMath.c','jsffi.c','model.c','render.c','script.c','simplex.c','spline.c', 'transform.c','prosperon.c', 'wildmatch.c', 'sprite.c', 'rtree.c', 'qjs_dmon.c', 'qjs_nota.c', 'qjs_enet.c', 'qjs_soloud.c', 'qjs_qr.c', 'qjs_wota.c', 'monocypher.c']
|
src += ['anim.c', 'config.c', 'datastream.c','font.c','HandmadeMath.c','jsffi.c','model.c','render.c','simplex.c','spline.c', 'transform.c','prosperon.c', 'wildmatch.c', 'sprite.c', 'rtree.c', 'qjs_dmon.c', 'qjs_nota.c', 'qjs_enet.c', 'qjs_soloud.c', 'qjs_qr.c', 'qjs_wota.c', 'monocypher.c']
|
||||||
|
|
||||||
# quirc src
|
# quirc src
|
||||||
src += ['thirdparty/quirc/quirc.c', 'thirdparty/quirc/decode.c','thirdparty/quirc/identify.c', 'thirdparty/quirc/version_db.c']
|
src += ['thirdparty/quirc/quirc.c', 'thirdparty/quirc/decode.c','thirdparty/quirc/identify.c', 'thirdparty/quirc/version_db.c']
|
||||||
|
|||||||
@@ -87,7 +87,7 @@ prosperon.PATH = [
|
|||||||
"scripts/modules/ext/",
|
"scripts/modules/ext/",
|
||||||
]
|
]
|
||||||
|
|
||||||
console.print("HERE")
|
|
||||||
|
|
||||||
// path is the path of a module or script to resolve
|
// path is the path of a module or script to resolve
|
||||||
var script_fn = function script_fn(path) {
|
var script_fn = function script_fn(path) {
|
||||||
@@ -132,6 +132,8 @@ function bare_load(file) {
|
|||||||
return undefined
|
return undefined
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
var res_cache = {}
|
var res_cache = {}
|
||||||
|
|
||||||
function console_rec(category, priority, line, file, msg) {
|
function console_rec(category, priority, line, file, msg) {
|
||||||
@@ -203,7 +205,7 @@ console.assert = function(op, str = `assertion failed [value '${op}']`) {
|
|||||||
if (!op) console.panic(str)
|
if (!op) console.panic(str)
|
||||||
}
|
}
|
||||||
|
|
||||||
//os.on('uncaught_exception', function(e) { console.log("HERRE!"); console.error(e); })
|
os.on('uncaught_exception', function(e) { console.error(e); })
|
||||||
|
|
||||||
console[prosperon.DOC] = {
|
console[prosperon.DOC] = {
|
||||||
doc: "The console object provides various logging, debugging, and output methods.",
|
doc: "The console object provides various logging, debugging, and output methods.",
|
||||||
@@ -286,6 +288,8 @@ globalThis.use = function use(file) {
|
|||||||
return use_cache[file]
|
return use_cache[file]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
globalThis.json = use('json')
|
globalThis.json = use('json')
|
||||||
var time = use('time')
|
var time = use('time')
|
||||||
|
|
||||||
@@ -413,11 +417,10 @@ function cant_kill() {
|
|||||||
throw Error("Can't kill an object in its spawning code. Move the kill command to awake.")
|
throw Error("Can't kill an object in its spawning code. Move the kill command to awake.")
|
||||||
}
|
}
|
||||||
|
|
||||||
// OK if return here
|
|
||||||
|
|
||||||
actor.toString = function() { return this[FILE] }
|
actor.toString = function() { return this[FILE] }
|
||||||
|
|
||||||
actor.spawn = function spawn(script, config, callback) {
|
actor.spawn = function spawn(script, config) {
|
||||||
|
|
||||||
if (this[DEAD]) throw new Error("Attempting to spawn on a dead actor")
|
if (this[DEAD]) throw new Error("Attempting to spawn on a dead actor")
|
||||||
var prog
|
var prog
|
||||||
if (!script) {
|
if (!script) {
|
||||||
@@ -470,13 +473,11 @@ actor.spawn = function spawn(script, config, callback) {
|
|||||||
configurable:false
|
configurable:false
|
||||||
})
|
})
|
||||||
|
|
||||||
if (callback) callback(underling, { message:"created" })
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
prog.prog_fn.call(underling)
|
prog.prog_fn.call(underling)
|
||||||
} catch(e) { throw e }
|
} catch(e) { throw e; }
|
||||||
|
|
||||||
if (underling[DEAD]) return undefined
|
if (underling[DEAD]) return undefined;
|
||||||
|
|
||||||
if (typeof config === 'object') Object.assign(underling, config)
|
if (typeof config === 'object') Object.assign(underling, config)
|
||||||
|
|
||||||
@@ -763,8 +764,8 @@ $_.unneeded = function(fn, seconds) {
|
|||||||
$_.unneeded[prosperon.DOC] = "registers a function that is called when the actor..."
|
$_.unneeded[prosperon.DOC] = "registers a function that is called when the actor..."
|
||||||
|
|
||||||
$_.delay = function(fn, seconds) {
|
$_.delay = function(fn, seconds) {
|
||||||
var id = os.addtimer(prosperon.id, fn, seconds);
|
var id = os.delay(fn, seconds);
|
||||||
return function() { os.removetimer(prosperon.id, id); }
|
return function() { os.removetimer(id); }
|
||||||
}
|
}
|
||||||
$_.delay[prosperon.DOC] = "used to schedule the invocation of a function..."
|
$_.delay[prosperon.DOC] = "used to schedule the invocation of a function..."
|
||||||
|
|
||||||
@@ -776,6 +777,8 @@ $_.couple = function(actor) {
|
|||||||
}
|
}
|
||||||
$_.couple[prosperon.DOC] = "causes this actor to stop when another actor stops."
|
$_.couple[prosperon.DOC] = "causes this actor to stop when another actor stops."
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
function actor_send(actor, message) {
|
function actor_send(actor, message) {
|
||||||
if (!$_.is_actor(actor)) throw new Error(`Must send to an actor object. Attempted send to ${json.encode(actor)}`)
|
if (!$_.is_actor(actor)) throw new Error(`Must send to an actor object. Attempted send to ${json.encode(actor)}`)
|
||||||
if (typeof message !== 'object') throw new Error('Must send an object record.')
|
if (typeof message !== 'object') throw new Error('Must send an object record.')
|
||||||
@@ -846,8 +849,6 @@ else prosperon.id = prosperon.args.id
|
|||||||
|
|
||||||
os.register_actor(prosperon.id, handle_local);
|
os.register_actor(prosperon.id, handle_local);
|
||||||
|
|
||||||
tracy.thread_name(prosperon.id)
|
|
||||||
|
|
||||||
$_.__ACTORDATA__.id = prosperon.id
|
$_.__ACTORDATA__.id = prosperon.id
|
||||||
|
|
||||||
if (prosperon.args.overling) overling = { __ACTORDATA__: {id: prosperon.args.overling} }
|
if (prosperon.args.overling) overling = { __ACTORDATA__: {id: prosperon.args.overling} }
|
||||||
@@ -875,6 +876,7 @@ function handle_actor_disconnect(id) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function handle_local(msg) {
|
function handle_local(msg) {
|
||||||
|
console.print("LOCAL!!!");
|
||||||
console.log("LOCAL MESSAGE");
|
console.log("LOCAL MESSAGE");
|
||||||
handle_message(wota.decode(msg))
|
handle_message(wota.decode(msg))
|
||||||
}
|
}
|
||||||
@@ -929,6 +931,8 @@ function handle_message(msg) {
|
|||||||
var greeter = greeters[msg.id]
|
var greeter = greeters[msg.id]
|
||||||
if (greeter) greeter({type: "actor_started", actor: create_actor(msg)})
|
if (greeter) greeter({type: "actor_started", actor: create_actor(msg)})
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
|
console.log('finished running main')
|
||||||
|
|
||||||
})()
|
})()
|
||||||
|
|||||||
@@ -15,9 +15,6 @@ os.exit[prosperon.DOC] = "Exit the application with the specified exit code."
|
|||||||
os.now[prosperon.DOC] = "Return current time (in seconds as a float) with high resolution."
|
os.now[prosperon.DOC] = "Return current time (in seconds as a float) with high resolution."
|
||||||
os.openurl[prosperon.DOC] = "Open the provided URL in the default web browser, if possible."
|
os.openurl[prosperon.DOC] = "Open the provided URL in the default web browser, if possible."
|
||||||
|
|
||||||
os.make_timer[prosperon.DOC] = "Create a new timer object that will call a specified function after a certain delay."
|
|
||||||
os.update_timers[prosperon.DOC] = "Advance all timers by the provided time delta (in seconds)."
|
|
||||||
|
|
||||||
os.sleep[prosperon.DOC] = "Block execution for the specified number of seconds."
|
os.sleep[prosperon.DOC] = "Block execution for the specified number of seconds."
|
||||||
os.battery_pct[prosperon.DOC] = "Return the battery level (percentage) or negative if unknown."
|
os.battery_pct[prosperon.DOC] = "Return the battery level (percentage) or negative if unknown."
|
||||||
os.battery_voltage[prosperon.DOC] = "Return the current battery voltage in volts, if available."
|
os.battery_voltage[prosperon.DOC] = "Return the current battery voltage in volts, if available."
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
#include "jsffi.h"
|
#include "jsffi.h"
|
||||||
#include "script.h"
|
|
||||||
#include "font.h"
|
#include "font.h"
|
||||||
#include "datastream.h"
|
#include "datastream.h"
|
||||||
#include "stb_ds.h"
|
#include "stb_ds.h"
|
||||||
@@ -6487,49 +6486,6 @@ JSC_SSCALL(os_eval,
|
|||||||
ret = JS_Eval(js, str2, strlen(str2), str, JS_EVAL_FLAG_STRICT);
|
ret = JS_Eval(js, str2, strlen(str2), str, JS_EVAL_FLAG_STRICT);
|
||||||
)
|
)
|
||||||
|
|
||||||
Uint32 timer_cb(prosperon_rt *actor, SDL_TimerID id, Uint32 interval)
|
|
||||||
{
|
|
||||||
int idx = hmgeti(actor->timers, id);
|
|
||||||
if (idx == -1) return 0;
|
|
||||||
|
|
||||||
SDL_LockMutex(actor->mutex);
|
|
||||||
JSValue cb = actor->timers[idx].value;
|
|
||||||
hmdel(actor->timers, id);
|
|
||||||
arrput(actor->events, cb);
|
|
||||||
SDL_UnlockMutex(actor->mutex);
|
|
||||||
|
|
||||||
actor_signal(actor);
|
|
||||||
}
|
|
||||||
|
|
||||||
JSC_CCALL(os_addtimer,
|
|
||||||
char *guid = JS_ToCString(js,argv[0]);
|
|
||||||
prosperon_rt *actor = get_actor(guid);
|
|
||||||
JS_FreeCString(js, guid);
|
|
||||||
if (!actor) return JS_ThrowInternalError(js, "Could not get actor from guid.");
|
|
||||||
|
|
||||||
Uint64 ns = js2number(js,argv[2]) * 1000000000.0f;
|
|
||||||
Uint32 id = SDL_AddTimerNS(ns, timer_cb, actor);
|
|
||||||
|
|
||||||
// appropriately add it to the actor
|
|
||||||
SDL_LockMutex(actor->mutex);
|
|
||||||
hmput(actor->timers, id, JS_DupValue(js,argv[1]));
|
|
||||||
SDL_UnlockMutex(actor->mutex);
|
|
||||||
)
|
|
||||||
|
|
||||||
JSC_CCALL(os_removetimer,
|
|
||||||
char *guid = JS_ToCString(js,argv[0]);
|
|
||||||
prosperon_rt *actor = get_actor(guid);
|
|
||||||
JS_FreeCString(js, guid);
|
|
||||||
if (!actor) return JS_ThrowInternalError(js, "Could not get actor from guid.");
|
|
||||||
|
|
||||||
Uint32 timer_id = js2number(js,argv[1]);
|
|
||||||
SDL_RemoveTimer(timer_id);
|
|
||||||
|
|
||||||
SDL_LockMutex(actor->mutex);
|
|
||||||
hmdel(actor->timers, timer_id);
|
|
||||||
SDL_UnlockMutex(actor->mutex);
|
|
||||||
)
|
|
||||||
|
|
||||||
// input: (encoded image data of jpg, png, bmp, tiff)
|
// input: (encoded image data of jpg, png, bmp, tiff)
|
||||||
JSC_CCALL(os_make_texture,
|
JSC_CCALL(os_make_texture,
|
||||||
size_t len;
|
size_t len;
|
||||||
@@ -7145,6 +7101,7 @@ JSC_CCALL(os_register_actor,
|
|||||||
rt->message_handle = JS_DupValue(js, argv[1]);
|
rt->message_handle = JS_DupValue(js, argv[1]);
|
||||||
rt->context = js;
|
rt->context = js;
|
||||||
JS_FreeCString(js, id);
|
JS_FreeCString(js, id);
|
||||||
|
printf("registered actor at %p with id %s, with function %p\n", rt, id, JS_VALUE_GET_PTR(rt->message_handle));
|
||||||
)
|
)
|
||||||
|
|
||||||
JSC_CCALL(os_mailbox_exist,
|
JSC_CCALL(os_mailbox_exist,
|
||||||
@@ -7215,8 +7172,8 @@ static const JSCFunctionListEntry js_os_funcs[] = {
|
|||||||
|
|
||||||
MIST_FUNC_DEF(os, mailbox_push, 2),
|
MIST_FUNC_DEF(os, mailbox_push, 2),
|
||||||
MIST_FUNC_DEF(os, mailbox_exist, 1),
|
MIST_FUNC_DEF(os, mailbox_exist, 1),
|
||||||
MIST_FUNC_DEF(os, addtimer, 3),
|
MIST_FUNC_DEF(actor, delay, 2),
|
||||||
MIST_FUNC_DEF(os, removetimer, 2),
|
MIST_FUNC_DEF(actor, removetimer, 1),
|
||||||
MIST_FUNC_DEF(os, register_actor, 2),
|
MIST_FUNC_DEF(os, register_actor, 2),
|
||||||
MIST_FUNC_DEF(os, unneeded, 2),
|
MIST_FUNC_DEF(os, unneeded, 2),
|
||||||
MIST_FUNC_DEF(os, destroy, 0),
|
MIST_FUNC_DEF(os, destroy, 0),
|
||||||
|
|||||||
@@ -1,185 +1,55 @@
|
|||||||
#include "script.h"
|
|
||||||
#include "physfs.h"
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <assert.h>
|
||||||
|
#include <inttypes.h>
|
||||||
|
#include <limits.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
|
||||||
|
#include "physfs.h"
|
||||||
#include "stb_ds.h"
|
#include "stb_ds.h"
|
||||||
|
|
||||||
#include "prosperon.h"
|
|
||||||
#include "jsffi.h"
|
#include "jsffi.h"
|
||||||
|
#include "prosperon.h"
|
||||||
|
|
||||||
|
#ifdef TRACY_ENABLE
|
||||||
|
#include <tracy/TracyC.h>
|
||||||
|
#if defined(__APPLE__)
|
||||||
|
#include <malloc/malloc.h>
|
||||||
|
#define MALLOC_OVERHEAD 0
|
||||||
|
#elif defined(_WIN32)
|
||||||
|
#include <malloc.h>
|
||||||
|
#define MALLOC_OVERHEAD 8
|
||||||
|
#elif defined(__linux__) || defined(__GLIBC__)
|
||||||
|
#define _GNU_SOURCE
|
||||||
|
#include <malloc.h>
|
||||||
|
#define MALLOC_OVERHEAD 8
|
||||||
|
#endif
|
||||||
|
#define likely(x) __builtin_expect(!!(x), 1)
|
||||||
|
#define unlikely(x) __builtin_expect(!!(x), 0)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define ENGINE "scripts/core/engine.js"
|
||||||
|
|
||||||
static prosperon_rt **ready_queue = NULL;
|
static prosperon_rt **ready_queue = NULL;
|
||||||
static prosperon_rt **slow_queue = NULL; // Slow actors
|
static prosperon_rt **slow_queue = NULL;
|
||||||
static prosperon_rt **reclaim_queue = NULL; // Actors needing reclamation
|
static prosperon_rt **reclaim_queue = NULL;
|
||||||
static SDL_Mutex *queue_mutex = NULL; // Protects queue access
|
static SDL_Mutex *queue_mutex = NULL;
|
||||||
static SDL_Condition *queue_cond = NULL; // Signals when work is available
|
static SDL_Condition *queue_cond = NULL;
|
||||||
|
static struct { char *key; prosperon_rt *value; } *actors = NULL;
|
||||||
|
static unsigned char *zip_buffer_global = NULL;
|
||||||
|
static char *prosperon = NULL;
|
||||||
|
|
||||||
static struct { char *key; prosperon_rt *value } *actors;
|
static void set_actor_state(prosperon_rt *actor);
|
||||||
|
|
||||||
static unsigned char *zip_buffer_global;
|
static Uint32 actor_remove_cb(prosperon_rt *actor, Uint32 id, Uint32 interval)
|
||||||
static char *prosperon;
|
|
||||||
|
|
||||||
SDL_ThreadID main_thread = 0;
|
|
||||||
|
|
||||||
void free_zip(void)
|
|
||||||
{
|
|
||||||
free(zip_buffer_global);
|
|
||||||
zip_buffer_global = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
int prosperon_mount_core()
|
|
||||||
{
|
|
||||||
size_t size;
|
|
||||||
FILE *f = fopen(prosperon, "rb");
|
|
||||||
if (!f) { perror("fopen"); return 0; }
|
|
||||||
if (fseek(f, 0, SEEK_END) != 0) { perror("fseek"); fclose(f); return 0; }
|
|
||||||
size = ftell(f);
|
|
||||||
if (size < 0) { perror("ftell"); fclose(f); return 0; }
|
|
||||||
zip_buffer_global = malloc(size);
|
|
||||||
if (!zip_buffer_global) { perror("malloc"); fclose(f); return 0; }
|
|
||||||
rewind(f);
|
|
||||||
if (fread(zip_buffer_global, 1, size, f) != (size_t)size) {
|
|
||||||
perror("fread");
|
|
||||||
free(zip_buffer_global);
|
|
||||||
fclose(f);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
fclose(f);
|
|
||||||
// Search backwards for the EOCD signature "PK\x05\x06".
|
|
||||||
// The EOCD record is at most 0xFFFF (65535) bytes plus 22 bytes long.
|
|
||||||
long max_comment_len = 0xFFFF;
|
|
||||||
long eocd_search_start = (size > (max_comment_len + 22)) ? (size - (max_comment_len + 22)) : 0;
|
|
||||||
long eocd_pos = -1;
|
|
||||||
for (long i = size - 22; i >= eocd_search_start; i--) {
|
|
||||||
if (zip_buffer_global[i] == 'P' &&
|
|
||||||
zip_buffer_global[i + 1] == 'K' &&
|
|
||||||
zip_buffer_global[i + 2] == 0x05 &&
|
|
||||||
zip_buffer_global[i + 3] == 0x06) {
|
|
||||||
eocd_pos = i;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (eocd_pos < 0) {
|
|
||||||
fprintf(stderr, "EOCD not found\n");
|
|
||||||
free(zip_buffer_global);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Parse the EOCD record.
|
|
||||||
// EOCD record layout (without the comment):
|
|
||||||
// Offset 0: 4 bytes signature ("PK\x05\x06")
|
|
||||||
// Offset 4: 2 bytes disk number
|
|
||||||
// Offset 6: 2 bytes disk with central directory
|
|
||||||
// Offset 8: 2 bytes number of central dir records on this disk
|
|
||||||
// Offset 10:2 bytes total number of central dir records
|
|
||||||
// Offset 12:4 bytes size of central directory (cd_size)
|
|
||||||
// Offset 16:4 bytes offset of start of central directory (cd_offset_rel, relative to zip start)
|
|
||||||
// Offset 20:2 bytes comment length
|
|
||||||
uint16_t comment_length = zip_buffer_global[eocd_pos + 20] |
|
|
||||||
(zip_buffer_global[eocd_pos + 21] << 8);
|
|
||||||
int eocd_size = 22 + comment_length;
|
|
||||||
uint32_t cd_size = zip_buffer_global[eocd_pos + 12] |
|
|
||||||
(zip_buffer_global[eocd_pos + 13] << 8) |
|
|
||||||
(zip_buffer_global[eocd_pos + 14] << 16) |
|
|
||||||
(zip_buffer_global[eocd_pos + 15] << 24);
|
|
||||||
uint32_t cd_offset_rel = zip_buffer_global[eocd_pos + 16] |
|
|
||||||
(zip_buffer_global[eocd_pos + 17] << 8) |
|
|
||||||
(zip_buffer_global[eocd_pos + 18] << 16) |
|
|
||||||
(zip_buffer_global[eocd_pos + 19] << 24);
|
|
||||||
|
|
||||||
uint32_t appended_zip_size = cd_offset_rel + cd_size + eocd_size;
|
|
||||||
long zip_offset = size - appended_zip_size;
|
|
||||||
if (zip_offset < 0 || zip_offset >= size) {
|
|
||||||
fprintf(stderr, "Invalid zip offset computed: %ld\n", zip_offset);
|
|
||||||
free(zip_buffer_global);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int ret = PHYSFS_mountMemory(zip_buffer_global + zip_offset, appended_zip_size, free_zip, "core.zip", NULL, 0);
|
|
||||||
|
|
||||||
if (!ret) {
|
|
||||||
printf("COULD NOT MOUNT! Reason: %s\n", PHYSFS_getErrorByCode(PHYSFS_getLastErrorCode()));
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
Uint32 actor_remove_cb(prosperon_rt *actor, Uint32 id, Uint32 interval)
|
|
||||||
{
|
{
|
||||||
|
printf("freeing actor after %ud\n", interval);
|
||||||
actor_free(actor);
|
actor_free(actor);
|
||||||
}
|
return 0;
|
||||||
|
|
||||||
void actor_free(prosperon_rt *actor)
|
|
||||||
{
|
|
||||||
// first, remove it from the queue
|
|
||||||
shdel(actors, actor->id);
|
|
||||||
JSContext *js = actor->context;
|
|
||||||
SDL_LockMutex(actor->mutex);
|
|
||||||
JS_FreeValue(js, actor->cycle_fn);
|
|
||||||
JS_FreeValue(js, actor->idx_buffer);
|
|
||||||
JS_FreeValue(js, actor->message_handle);
|
|
||||||
JS_FreeValue(js, actor->on_exception);
|
|
||||||
|
|
||||||
SDL_RemoveTimer(actor->ar);
|
|
||||||
|
|
||||||
for (int i = 0; i < arrlen(actor->js_swapchains); i++)
|
|
||||||
JS_FreeValue(js, actor->js_swapchains[i]);
|
|
||||||
|
|
||||||
for (int i = 0; i < arrlen(actor->events); i++)
|
|
||||||
JS_FreeValue(js, actor->events[i]);
|
|
||||||
|
|
||||||
for (int i = 0; i < hmlen(actor->timers); i++)
|
|
||||||
JS_FreeValue(js, actor->timers[i].value);
|
|
||||||
|
|
||||||
// free(actor->timers);
|
|
||||||
arrfree(actor->js_swapchains);
|
|
||||||
arrfree(actor->events);
|
|
||||||
arrfree(actor->messages);
|
|
||||||
arrfree(actor->module_registry);
|
|
||||||
|
|
||||||
SDL_DestroyMutex(actor->mutex);
|
|
||||||
|
|
||||||
JSRuntime *rt = JS_GetRuntime(js);
|
|
||||||
JS_FreeContext(js);
|
|
||||||
JS_FreeRuntime(rt);
|
|
||||||
free(actor->id);
|
|
||||||
free(actor);
|
|
||||||
}
|
|
||||||
|
|
||||||
void set_actor_state(prosperon_rt *actor)
|
|
||||||
{
|
|
||||||
SDL_LockMutex(actor->mutex);
|
|
||||||
if (arrlen(actor->messages) == 0) {
|
|
||||||
actor->state = ACTOR_IDLE;
|
|
||||||
actor->ar = SDL_AddTimerNS(1e9, actor_remove_cb, actor);
|
|
||||||
} else {
|
|
||||||
actor->state = ACTOR_READY;
|
|
||||||
SDL_LockMutex(queue_mutex);
|
|
||||||
arrput(ready_queue, actor);
|
|
||||||
SDL_SignalCondition(queue_cond);
|
|
||||||
SDL_UnlockMutex(queue_mutex);
|
|
||||||
}
|
|
||||||
SDL_UnlockMutex(actor->mutex);
|
|
||||||
}
|
|
||||||
|
|
||||||
// this function should be called to spin off a new thread with actor
|
|
||||||
prosperon_rt *create_actor(int argc, char **argv)
|
|
||||||
{
|
|
||||||
prosperon_rt *rt = calloc(sizeof(*rt),1);
|
|
||||||
rt->cmd.argc = argc;
|
|
||||||
rt->cmd.argv = argv;
|
|
||||||
rt->cycle_fn = JS_UNDEFINED;
|
|
||||||
rt->idx_buffer = JS_UNDEFINED;
|
|
||||||
|
|
||||||
script_startup(rt);
|
|
||||||
|
|
||||||
set_actor_state(rt);
|
|
||||||
|
|
||||||
return rt;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void js_dofree(JSRuntime *rt, void *opaque, void *ptr)
|
void js_dofree(JSRuntime *rt, void *opaque, void *ptr)
|
||||||
@@ -187,194 +57,157 @@ void js_dofree(JSRuntime *rt, void *opaque, void *ptr)
|
|||||||
js_free_rt(rt, ptr);
|
js_free_rt(rt, ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
void run_actor_turn(prosperon_rt *actor)
|
SDL_ThreadID main_thread = 0;
|
||||||
|
SDL_TLSID prosperon_id;
|
||||||
|
|
||||||
|
#ifdef TRACY_ENABLE
|
||||||
|
static size_t js_tracy_malloc_usable_size(const void *ptr)
|
||||||
{
|
{
|
||||||
SDL_LockMutex(actor->mutex);
|
#if defined(__APPLE__)
|
||||||
actor->state = ACTOR_RUNNING;
|
return malloc_size(ptr);
|
||||||
|
#elif defined(_WIN32)
|
||||||
// Process all messages until the message queue is empty
|
return _msize((void *)ptr);
|
||||||
while (arrlen(actor->messages) > 0) {
|
#elif defined(EMSCRIPTEN)
|
||||||
struct message msg = actor->messages[0];
|
|
||||||
arrdel(actor->messages, 0);
|
|
||||||
JSValue arg = JS_NewArrayBuffer(actor->context, msg.data, msg.size, js_dofree, NULL, 0);
|
|
||||||
JSValue result = JS_Call(actor->context, actor->message_handle, JS_UNDEFINED, 1, &arg);
|
|
||||||
uncaught_exception(actor->context, result);
|
|
||||||
JS_FreeValue(actor->context, arg); // Free the argument after use
|
|
||||||
}
|
|
||||||
|
|
||||||
// After all messages are processed, process one event if any exist
|
|
||||||
while (arrlen(actor->messages) > 0) {
|
|
||||||
JSValue event = actor->events[0];
|
|
||||||
arrdel(actor->events, 0);
|
|
||||||
JSValue result = JS_Call(actor->context, event, JS_UNDEFINED, 0, NULL);
|
|
||||||
uncaught_exception(actor->context, result);
|
|
||||||
JS_FreeValue(actor->context, event);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update state and re-queue if necessary
|
|
||||||
set_actor_state(actor);
|
|
||||||
SDL_UnlockMutex(actor->mutex);
|
|
||||||
}
|
|
||||||
|
|
||||||
int reclaimer_thread(void *data)
|
|
||||||
{
|
|
||||||
while (true) {
|
|
||||||
SDL_LockMutex(queue_mutex);
|
|
||||||
while (arrlen(reclaim_queue) == 0)
|
|
||||||
SDL_WaitCondition(queue_cond, queue_mutex);
|
|
||||||
|
|
||||||
prosperon_rt *actor = reclaim_queue[0];
|
|
||||||
arrdel(reclaim_queue, 0);
|
|
||||||
SDL_UnlockMutex(queue_mutex);
|
|
||||||
|
|
||||||
SDL_LockMutex(actor->mutex);
|
|
||||||
if (actor->state == ACTOR_EXHAUSTED) {
|
|
||||||
actor->state = ACTOR_RECLAIMING;
|
|
||||||
JS_RunGC(JS_GetRuntime(actor->context));
|
|
||||||
}
|
|
||||||
SDL_UnlockMutex(actor->mutex);
|
|
||||||
|
|
||||||
actor_signal(actor);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int crank_actor()
|
|
||||||
{
|
|
||||||
while (true) {
|
|
||||||
prosperon_rt *actor = NULL;
|
|
||||||
SDL_LockMutex(queue_mutex);
|
|
||||||
if (arrlen(ready_queue) > 0) {
|
|
||||||
actor = ready_queue[0];
|
|
||||||
arrdel(ready_queue, 0);
|
|
||||||
} else if (arrlen(slow_queue) > 0) {
|
|
||||||
actor = slow_queue[0];
|
|
||||||
arrdel(slow_queue, 0);
|
|
||||||
} else {
|
|
||||||
SDL_WaitCondition(queue_cond, queue_mutex);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
SDL_UnlockMutex(queue_mutex);
|
|
||||||
if (actor)
|
|
||||||
run_actor_turn(actor);
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
#elif defined(__linux__) || defined(__GLIBC__)
|
||||||
|
return malloc_usable_size((void *)ptr);
|
||||||
|
#else
|
||||||
|
return malloc_usable_size((void *)ptr);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static void signal_handler(int sig) {
|
static void *js_tracy_malloc(JSMallocState *s, size_t size)
|
||||||
const char *str = NULL;
|
|
||||||
switch(sig) {
|
|
||||||
case SIGABRT:
|
|
||||||
str = "SIGABRT";
|
|
||||||
break;
|
|
||||||
case SIGFPE:
|
|
||||||
str = "SIGFPE";
|
|
||||||
break;
|
|
||||||
case SIGILL:
|
|
||||||
str = "SIGILL";
|
|
||||||
break;
|
|
||||||
case SIGINT:
|
|
||||||
str = "SIGINT";
|
|
||||||
break;
|
|
||||||
case SIGSEGV:
|
|
||||||
str = "SIGSEGV";
|
|
||||||
break;
|
|
||||||
case SIGTERM:
|
|
||||||
str = "SIGTERM";
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (!str) return;
|
|
||||||
|
|
||||||
for (int i = 0; i < shlen(actors); i++) {
|
|
||||||
prosperon_rt *main = actors[i].value;
|
|
||||||
JSContext *js = main->context;
|
|
||||||
script_evalf(js, "prosperon.dispatch('%s')", str);
|
|
||||||
}
|
|
||||||
|
|
||||||
switch(sig) {
|
|
||||||
case SIGTERM:
|
|
||||||
exit(1);
|
|
||||||
case SIGINT:
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void exit_handler()
|
|
||||||
{
|
{
|
||||||
for (int i = 0; i < shlen(actors); i++) {
|
void *ptr;
|
||||||
prosperon_rt *main = actors[i].value;
|
assert(size != 0);
|
||||||
JSContext *js = main->context;
|
if (unlikely(s->malloc_size + size > s->malloc_limit)) return NULL;
|
||||||
script_evalf(js, "prosperon.dispatch('exit')", NULL);
|
ptr = malloc(size);
|
||||||
}
|
if (!ptr) return NULL;
|
||||||
|
s->malloc_count++;
|
||||||
|
s->malloc_size += js_tracy_malloc_usable_size(ptr) + MALLOC_OVERHEAD;
|
||||||
|
TracyCAllocN(ptr, js_tracy_malloc_usable_size(ptr) + MALLOC_OVERHEAD, "quickjs");
|
||||||
|
return ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char **argv) {
|
static void js_tracy_free(JSMallocState *s, void *ptr)
|
||||||
SDL_Init(SDL_INIT_EVENTS | SDL_INIT_VIDEO);
|
{
|
||||||
int cores = SDL_GetNumLogicalCPUCores();
|
if (!ptr) return;
|
||||||
if (cores == 1) {
|
s->malloc_count--;
|
||||||
printf("Platform has only one core!\n");
|
s->malloc_size -= js_tracy_malloc_usable_size(ptr) + MALLOC_OVERHEAD;
|
||||||
return 1;
|
TracyCFreeN(ptr, "quickjs");
|
||||||
|
free(ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void *js_tracy_realloc(JSMallocState *s, void *ptr, size_t size)
|
||||||
|
{
|
||||||
|
size_t old_size;
|
||||||
|
if (!ptr) return size ? js_tracy_malloc(s, size) : NULL;
|
||||||
|
old_size = js_tracy_malloc_usable_size(ptr);
|
||||||
|
if (!size) {
|
||||||
|
s->malloc_count--;
|
||||||
|
s->malloc_size -= old_size + MALLOC_OVERHEAD;
|
||||||
|
TracyCFreeN(ptr, "quickjs");
|
||||||
|
free(ptr);
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
|
if (s->malloc_size + size - old_size > s->malloc_limit) return NULL;
|
||||||
main_thread = SDL_GetCurrentThreadID();
|
TracyCFreeN(ptr, "quickjs");
|
||||||
|
ptr = realloc(ptr, size);
|
||||||
|
if (!ptr) return NULL;
|
||||||
|
s->malloc_size += js_tracy_malloc_usable_size(ptr) - old_size;
|
||||||
|
TracyCAllocN(ptr, js_tracy_malloc_usable_size(ptr) + MALLOC_OVERHEAD, "quickjs");
|
||||||
|
return ptr;
|
||||||
|
}
|
||||||
|
|
||||||
if (!main_thread) {
|
static const JSMallocFunctions tracy_malloc_funcs = {
|
||||||
printf("Platform does not support threads!\n");
|
js_tracy_malloc,
|
||||||
return 1;
|
js_tracy_free,
|
||||||
|
js_tracy_realloc,
|
||||||
|
js_tracy_malloc_usable_size
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static void free_zip(void)
|
||||||
|
{
|
||||||
|
free(zip_buffer_global);
|
||||||
|
zip_buffer_global = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
int prosperon_mount_core(void)
|
||||||
|
{
|
||||||
|
size_t size;
|
||||||
|
FILE *f = fopen(prosperon, "rb");
|
||||||
|
if (!f) return perror("fopen"), 0;
|
||||||
|
if (fseek(f, 0, SEEK_END) != 0) return perror("fseek"), fclose(f), 0;
|
||||||
|
size = ftell(f);
|
||||||
|
if (size < 0) return perror("ftell"), fclose(f), 0;
|
||||||
|
zip_buffer_global = malloc(size);
|
||||||
|
if (!zip_buffer_global) return perror("malloc"), fclose(f), 0;
|
||||||
|
rewind(f);
|
||||||
|
if (fread(zip_buffer_global, 1, size, f) != size) {
|
||||||
|
perror("fread");
|
||||||
|
free(zip_buffer_global);
|
||||||
|
fclose(f);
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
fclose(f);
|
||||||
|
|
||||||
prosperon = argv[0];
|
long max_comment_len = 0xFFFF;
|
||||||
|
long eocd_search_start = (size > max_comment_len + 22) ? size - (max_comment_len + 22) : 0;
|
||||||
|
long eocd_pos = -1;
|
||||||
|
for (long i = size - 22; i >= eocd_search_start; i--)
|
||||||
|
if (zip_buffer_global[i] == 'P' && zip_buffer_global[i + 1] == 'K' &&
|
||||||
|
zip_buffer_global[i + 2] == 0x05 && zip_buffer_global[i + 3] == 0x06) {
|
||||||
|
eocd_pos = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (eocd_pos < 0) return fprintf(stderr, "EOCD not found\n"), free(zip_buffer_global), 0;
|
||||||
|
|
||||||
PHYSFS_init(argv[0]);
|
uint16_t comment_length = zip_buffer_global[eocd_pos + 20] | (zip_buffer_global[eocd_pos + 21] << 8);
|
||||||
const char *base = PHYSFS_getBaseDir();
|
int eocd_size = 22 + comment_length;
|
||||||
PHYSFS_setWriteDir(base);
|
uint32_t cd_size = zip_buffer_global[eocd_pos + 12] | (zip_buffer_global[eocd_pos + 13] << 8) |
|
||||||
|
(zip_buffer_global[eocd_pos + 14] << 16) | (zip_buffer_global[eocd_pos + 15] << 24);
|
||||||
|
uint32_t cd_offset_rel = zip_buffer_global[eocd_pos + 16] | (zip_buffer_global[eocd_pos + 17] << 8) |
|
||||||
|
(zip_buffer_global[eocd_pos + 18] << 16) | (zip_buffer_global[eocd_pos + 19] << 24);
|
||||||
|
uint32_t appended_zip_size = cd_offset_rel + cd_size + eocd_size;
|
||||||
|
long zip_offset = size - appended_zip_size;
|
||||||
|
if (zip_offset < 0 || zip_offset >= size) return fprintf(stderr, "Invalid zip offset: %ld\n", zip_offset), free(zip_buffer_global), 0;
|
||||||
|
|
||||||
PHYSFS_mount(base, "/", 0);
|
int ret = PHYSFS_mountMemory(zip_buffer_global + zip_offset, appended_zip_size, free_zip, "core.zip", NULL, 0);
|
||||||
int mounted = prosperon_mount_core();
|
if (!ret) printf("COULD NOT MOUNT! Reason: %s\n", PHYSFS_getErrorByCode(PHYSFS_getLastErrorCode()));
|
||||||
if (!mounted)
|
return ret;
|
||||||
mounted = PHYSFS_mount("core.zip", NULL, 0);
|
}
|
||||||
if (!mounted) {
|
|
||||||
printf("Could not mount core. Reason: %s\n", PHYSFS_getErrorByCode(PHYSFS_getLastErrorCode()));
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
char **margv = malloc(sizeof(char*));
|
prosperon_rt *create_actor(int argc, char **argv)
|
||||||
for (int i = 0; i < argc; i++)
|
{
|
||||||
margv[i] = strdup(argv[i]);
|
prosperon_rt *actor = calloc(sizeof(*actor), 1);
|
||||||
|
actor->cmd.argc = argc;
|
||||||
create_actor(argc, margv);
|
actor->cmd.argv = argv;
|
||||||
|
actor->cycle_fn = JS_UNDEFINED;
|
||||||
queue_mutex = SDL_CreateMutex();
|
actor->idx_buffer = JS_UNDEFINED;
|
||||||
queue_cond = SDL_CreateCondition();
|
actor->message_handle = JS_UNDEFINED;
|
||||||
|
actor->unneeded = JS_UNDEFINED;
|
||||||
|
actor->on_exception = JS_UNDEFINED;
|
||||||
|
arrsetcap(actor->messages, 5);
|
||||||
|
actor->mutex = SDL_CreateMutex();
|
||||||
|
SDL_LockMutex(actor->mutex);
|
||||||
|
printf("created actor %p\n", actor);
|
||||||
|
script_startup(actor);
|
||||||
|
const char *fnstr = JS_ToCString(actor->context, actor->message_handle);
|
||||||
|
printf("WWWWWW AFTER MAKE ACTOR WWWWWW\n");
|
||||||
|
printf("NOW??? actor turn %p , fn at %p\n", actor, JS_VALUE_GET_PTR(actor->message_handle));
|
||||||
|
printf("%s\n", fnstr);
|
||||||
|
JS_FreeCString(actor->context, fnstr);
|
||||||
|
|
||||||
for (int i = 0; i < 1; i++)
|
set_actor_state(actor);
|
||||||
SDL_CreateThread(crank_actor, "actor_runner", NULL);
|
SDL_UnlockMutex(actor->mutex);
|
||||||
|
return actor;
|
||||||
SDL_CreateThread(reclaimer_thread, "reclaimer", NULL);
|
|
||||||
|
|
||||||
signal(SIGINT, signal_handler);
|
|
||||||
signal(SIGTERM, signal_handler);
|
|
||||||
signal(SIGSEGV, signal_handler);
|
|
||||||
signal(SIGABRT, signal_handler);
|
|
||||||
atexit(exit_handler);
|
|
||||||
|
|
||||||
SDL_Event *event;
|
|
||||||
while (SDL_WaitEvent(event)) {
|
|
||||||
printf("Got event!\n");
|
|
||||||
if (event->type == SDL_EVENT_QUIT)
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
prosperon_rt *get_actor(char *id)
|
prosperon_rt *get_actor(char *id)
|
||||||
{
|
{
|
||||||
int idx = shgeti(actors, id);
|
int idx = shgeti(actors, id);
|
||||||
if (idx == -1) return NULL;
|
return idx == -1 ? NULL : actors[idx].value;
|
||||||
|
|
||||||
return actors[idx].value;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
char *register_actor(char *id, prosperon_rt *actor)
|
char *register_actor(char *id, prosperon_rt *actor)
|
||||||
@@ -389,13 +222,9 @@ void send_message(prosperon_rt *target, struct message msg)
|
|||||||
{
|
{
|
||||||
SDL_LockMutex(target->mutex);
|
SDL_LockMutex(target->mutex);
|
||||||
arrput(target->messages, msg);
|
arrput(target->messages, msg);
|
||||||
if (target->ar) {
|
if (target->ar) SDL_RemoveTimer(target->ar), target->ar = 0;
|
||||||
SDL_RemoveTimer(target->ar);
|
|
||||||
target->ar = 0;
|
|
||||||
}
|
|
||||||
SDL_UnlockMutex(target->mutex);
|
|
||||||
|
|
||||||
actor_signal(target);
|
actor_signal(target);
|
||||||
|
SDL_UnlockMutex(target->mutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
void actor_signal(prosperon_rt *actor)
|
void actor_signal(prosperon_rt *actor)
|
||||||
@@ -408,6 +237,290 @@ void actor_signal(prosperon_rt *actor)
|
|||||||
SDL_SignalCondition(queue_cond);
|
SDL_SignalCondition(queue_cond);
|
||||||
SDL_UnlockMutex(queue_mutex);
|
SDL_UnlockMutex(queue_mutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
SDL_UnlockMutex(actor->mutex);
|
SDL_UnlockMutex(actor->mutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void set_actor_state(prosperon_rt *actor)
|
||||||
|
{
|
||||||
|
SDL_LockMutex(actor->mutex);
|
||||||
|
if (arrlen(actor->messages) == 0) {
|
||||||
|
actor->state = ACTOR_IDLE;
|
||||||
|
actor->ar = SDL_AddTimerNS(100e9, actor_remove_cb, actor);
|
||||||
|
} else {
|
||||||
|
actor->state = ACTOR_READY;
|
||||||
|
SDL_LockMutex(queue_mutex);
|
||||||
|
arrput(ready_queue, actor);
|
||||||
|
SDL_SignalCondition(queue_cond);
|
||||||
|
SDL_UnlockMutex(queue_mutex);
|
||||||
|
}
|
||||||
|
SDL_UnlockMutex(actor->mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
void actor_turn(prosperon_rt *actor)
|
||||||
|
{
|
||||||
|
printf("AAAAAAAAAAAAAAAAA ACTOR TAKE TURN %p\n", actor);
|
||||||
|
printf("actor turn %p , fn at %p\n", actor, JS_VALUE_GET_PTR(actor->message_handle));
|
||||||
|
|
||||||
|
SDL_LockMutex(actor->mutex);
|
||||||
|
actor->state = ACTOR_RUNNING;
|
||||||
|
|
||||||
|
const char *fnstr = JS_ToCString(actor->context, actor->message_handle);
|
||||||
|
printf("NOW??? actor turn %p , fn at %p. S A FN???? %d\n", actor, JS_VALUE_GET_PTR(actor->message_handle), JS_IsFunction(actor->context, actor->message_handle));
|
||||||
|
printf("%p\n", fnstr);
|
||||||
|
JS_FreeCString(actor->context, fnstr);
|
||||||
|
|
||||||
|
|
||||||
|
while (arrlen(actor->messages) > 0) {
|
||||||
|
struct message msg = actor->messages[0];
|
||||||
|
arrdel(actor->messages, 0);
|
||||||
|
JSValue arg = JS_NewArrayBuffer(actor->context, msg.data, msg.size, js_dofree, NULL, 0);
|
||||||
|
JSValue result = JS_Call(actor->context, actor->message_handle, JS_UNDEFINED, 1, &arg);
|
||||||
|
uncaught_exception(actor->context, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
while (arrlen(actor->events) > 0) {
|
||||||
|
JSValue event = actor->events[0];
|
||||||
|
arrdel(actor->events, 0);
|
||||||
|
JSValue result = JS_Call(actor->context, event, JS_UNDEFINED, 0, NULL);
|
||||||
|
uncaught_exception(actor->context, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
set_actor_state(actor);
|
||||||
|
SDL_UnlockMutex(actor->mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
void actor_free(prosperon_rt *actor)
|
||||||
|
{
|
||||||
|
printf("KILLING ACTOR %p\n", actor);
|
||||||
|
shdel(actors, actor->id);
|
||||||
|
JSContext *js = actor->context;
|
||||||
|
SDL_LockMutex(actor->mutex);
|
||||||
|
JS_FreeValue(js, actor->cycle_fn);
|
||||||
|
JS_FreeValue(js, actor->idx_buffer);
|
||||||
|
JS_FreeValue(js, actor->message_handle);
|
||||||
|
JS_FreeValue(js, actor->on_exception);
|
||||||
|
SDL_RemoveTimer(actor->ar);
|
||||||
|
for (int i = 0; i < arrlen(actor->js_swapchains); i++) JS_FreeValue(js, actor->js_swapchains[i]);
|
||||||
|
for (int i = 0; i < arrlen(actor->events); i++) JS_FreeValue(js, actor->events[i]);
|
||||||
|
for (int i = 0; i < hmlen(actor->timers); i++) JS_FreeValue(js, actor->timers[i].value);
|
||||||
|
arrfree(actor->js_swapchains);
|
||||||
|
arrfree(actor->events);
|
||||||
|
arrfree(actor->messages);
|
||||||
|
arrfree(actor->module_registry);
|
||||||
|
SDL_DestroyMutex(actor->mutex);
|
||||||
|
JSRuntime *rt = JS_GetRuntime(js);
|
||||||
|
JS_FreeContext(js);
|
||||||
|
JS_FreeRuntime(rt);
|
||||||
|
free(actor->id);
|
||||||
|
free(actor);
|
||||||
|
}
|
||||||
|
|
||||||
|
Uint32 actor_timer_cb(prosperon_rt *actor, SDL_TimerID id, Uint32 interval)
|
||||||
|
{
|
||||||
|
int idx = hmgeti(actor->timers, id);
|
||||||
|
if (idx == -1) return 0;
|
||||||
|
SDL_LockMutex(actor->mutex);
|
||||||
|
JSValue cb = actor->timers[idx].value;
|
||||||
|
hmdel(actor->timers, id);
|
||||||
|
arrput(actor->events, cb);
|
||||||
|
SDL_UnlockMutex(actor->mutex);
|
||||||
|
actor_signal(actor);
|
||||||
|
return interval;
|
||||||
|
}
|
||||||
|
|
||||||
|
JSValue js_actor_delay(JSContext *js, JSValue self, int argc, JSValue *argv)
|
||||||
|
{
|
||||||
|
prosperon_rt *actor = JS_GetContextOpaque(js);
|
||||||
|
double seconds;
|
||||||
|
JS_ToFloat64(js, &seconds, argv[2]);
|
||||||
|
Uint64 ns = seconds * 1000000000.0f;
|
||||||
|
Uint32 id = SDL_AddTimerNS(ns, actor_timer_cb, actor);
|
||||||
|
SDL_LockMutex(actor->mutex);
|
||||||
|
hmput(actor->timers, id, JS_DupValue(js, argv[1]));
|
||||||
|
SDL_UnlockMutex(actor->mutex);
|
||||||
|
return JS_UNDEFINED;
|
||||||
|
}
|
||||||
|
|
||||||
|
JSValue js_actor_removetimer(JSContext *js, JSValue self, int argc, JSValue *argv)
|
||||||
|
{
|
||||||
|
prosperon_rt *actor = JS_GetContextOpaque(js);
|
||||||
|
Uint32 timer_id;
|
||||||
|
JS_ToUint32(js, &timer_id, argv[1]);
|
||||||
|
SDL_RemoveTimer(timer_id);
|
||||||
|
SDL_LockMutex(actor->mutex);
|
||||||
|
hmdel(actor->timers, timer_id);
|
||||||
|
SDL_UnlockMutex(actor->mutex);
|
||||||
|
return JS_UNDEFINED;
|
||||||
|
}
|
||||||
|
|
||||||
|
void script_startup(prosperon_rt *prt)
|
||||||
|
{
|
||||||
|
JSRuntime *rt;
|
||||||
|
#ifdef TRACY_ENABLE
|
||||||
|
rt = JS_NewRuntime2(&tracy_malloc_funcs, NULL);
|
||||||
|
#else
|
||||||
|
rt = JS_NewRuntime();
|
||||||
|
#endif
|
||||||
|
JSContext *js = JS_NewContextRaw(rt);
|
||||||
|
JS_AddIntrinsicBaseObjects(js);
|
||||||
|
JS_AddIntrinsicEval(js);
|
||||||
|
JS_AddIntrinsicRegExp(js);
|
||||||
|
JS_AddIntrinsicJSON(js);
|
||||||
|
JS_AddIntrinsicMapSet(js);
|
||||||
|
JS_AddIntrinsicTypedArrays(js);
|
||||||
|
JS_AddIntrinsicBigInt(js);
|
||||||
|
JS_AddIntrinsicBigFloat(js);
|
||||||
|
JS_AddIntrinsicBigDecimal(js);
|
||||||
|
JS_AddIntrinsicOperators(js);
|
||||||
|
JS_EnableBignumExt(js, 1);
|
||||||
|
JS_SetContextOpaque(js, prt);
|
||||||
|
prt->context = js;
|
||||||
|
ffi_load(js);
|
||||||
|
|
||||||
|
PHYSFS_File *eng = PHYSFS_openRead(ENGINE);
|
||||||
|
if (!eng) {
|
||||||
|
printf("Could not open file! %s\n", PHYSFS_getErrorByCode(PHYSFS_getLastErrorCode()));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
PHYSFS_Stat stat;
|
||||||
|
PHYSFS_stat(ENGINE, &stat);
|
||||||
|
void *data = malloc(stat.filesize);
|
||||||
|
PHYSFS_readBytes(eng, data, stat.filesize);
|
||||||
|
PHYSFS_close(eng);
|
||||||
|
SDL_LockMutex(prt->mutex);
|
||||||
|
JSValue v = JS_Eval(js, data, strlen(data), ENGINE, JS_EVAL_FLAG_STRICT);
|
||||||
|
uncaught_exception(js, v);
|
||||||
|
SDL_UnlockMutex(prt->mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
void uncaught_exception(JSContext *js, JSValue v)
|
||||||
|
{
|
||||||
|
JS_FreeValue(js, v);
|
||||||
|
return;
|
||||||
|
prosperon_rt *rt = JS_GetContextOpaque(js);
|
||||||
|
SDL_LockMutex(rt->mutex);
|
||||||
|
if (!JS_HasException(js)) goto END;
|
||||||
|
|
||||||
|
JSValue exp = JS_GetException(js);
|
||||||
|
printf("error in actor %p\n", rt);
|
||||||
|
printf("value is tagged with %d. is error? %d\n", JS_VALUE_GET_TAG(exp), JS_IsError(js, exp));
|
||||||
|
if (JS_IsFunction(js, rt->on_exception)) {
|
||||||
|
JSValue ret = JS_Call(js, rt->on_exception, JS_UNDEFINED, 1, &exp);
|
||||||
|
JS_FreeValue(js, ret);
|
||||||
|
} else {
|
||||||
|
const char *msg = JS_ToCString(js, exp);
|
||||||
|
JSValue stack = JS_GetPropertyStr(js, exp, "stack");
|
||||||
|
const char *st = JS_ToCString(js, stack);
|
||||||
|
printf("Unhandled exception: %s\n%s\n", msg, st);
|
||||||
|
JS_FreeCString(js, st);
|
||||||
|
JS_FreeCString(js, msg);
|
||||||
|
JS_FreeValue(js, stack);
|
||||||
|
}
|
||||||
|
JS_FreeValue(js, exp);
|
||||||
|
END:
|
||||||
|
SDL_UnlockMutex(rt->mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
void script_evalf(JSContext *js, const char *format, ...)
|
||||||
|
{
|
||||||
|
prosperon_rt *rt = JS_GetContextOpaque(js);
|
||||||
|
SDL_LockMutex(rt->mutex);
|
||||||
|
va_list args;
|
||||||
|
va_start(args, format);
|
||||||
|
int len = vsnprintf(NULL, 0, format, args);
|
||||||
|
va_end(args);
|
||||||
|
char *eval = malloc(len + 1);
|
||||||
|
va_start(args, format);
|
||||||
|
vsnprintf(eval, len + 1, format, args);
|
||||||
|
va_end(args);
|
||||||
|
JSValue obj = JS_Eval(js, eval, len, "C eval", JS_EVAL_FLAG_STRICT);
|
||||||
|
free(eval);
|
||||||
|
uncaught_exception(js, obj);
|
||||||
|
SDL_UnlockMutex(rt->mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int crank_actor(void *data)
|
||||||
|
{
|
||||||
|
while (true) {
|
||||||
|
prosperon_rt *actor = NULL;
|
||||||
|
SDL_LockMutex(queue_mutex);
|
||||||
|
if (arrlen(ready_queue) > 0) actor = ready_queue[0], arrdel(ready_queue, 0);
|
||||||
|
else if (arrlen(slow_queue) > 0) actor = slow_queue[0], arrdel(slow_queue, 0);
|
||||||
|
else {
|
||||||
|
SDL_WaitCondition(queue_cond, queue_mutex);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
SDL_UnlockMutex(queue_mutex);
|
||||||
|
if (actor) actor_turn(actor);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void signal_handler(int sig)
|
||||||
|
{
|
||||||
|
const char *str = NULL;
|
||||||
|
switch (sig) {
|
||||||
|
case SIGABRT: str = "SIGABRT"; break;
|
||||||
|
case SIGFPE: str = "SIGFPE"; break;
|
||||||
|
case SIGILL: str = "SIGILL"; break;
|
||||||
|
case SIGINT: str = "SIGINT"; break;
|
||||||
|
case SIGSEGV: str = "SIGSEGV"; break;
|
||||||
|
case SIGTERM: str = "SIGTERM"; break;
|
||||||
|
}
|
||||||
|
if (!str) return;
|
||||||
|
for (int i = 0; i < shlen(actors); i++) {
|
||||||
|
prosperon_rt *main = actors[i].value;
|
||||||
|
JSContext *js = main->context;
|
||||||
|
script_evalf(js, "prosperon.dispatch('%s')", str);
|
||||||
|
}
|
||||||
|
if (sig == SIGTERM || sig == SIGINT) exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void exit_handler(void)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < shlen(actors); i++) {
|
||||||
|
prosperon_rt *main = actors[i].value;
|
||||||
|
JSContext *js = main->context;
|
||||||
|
script_evalf(js, "prosperon.dispatch('exit')");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
SDL_Init(SDL_INIT_EVENTS | SDL_INIT_VIDEO);
|
||||||
|
int cores = SDL_GetNumLogicalCPUCores();
|
||||||
|
if (cores == 1) return printf("Platform has only one core!\n"), 1;
|
||||||
|
main_thread = SDL_GetCurrentThreadID();
|
||||||
|
if (!main_thread) return printf("Platform does not support threads!\n"), 1;
|
||||||
|
|
||||||
|
prosperon = argv[0];
|
||||||
|
PHYSFS_init(argv[0]);
|
||||||
|
const char *base = PHYSFS_getBaseDir();
|
||||||
|
PHYSFS_setWriteDir(base);
|
||||||
|
PHYSFS_mount(base, "/", 0);
|
||||||
|
int mounted = prosperon_mount_core();
|
||||||
|
if (!mounted) mounted = PHYSFS_mount("core.zip", NULL, 0);
|
||||||
|
if (!mounted) return printf("Could not mount core. Reason: %s\n", PHYSFS_getErrorByCode(PHYSFS_getLastErrorCode())), 1;
|
||||||
|
|
||||||
|
queue_mutex = SDL_CreateMutex();
|
||||||
|
queue_cond = SDL_CreateCondition();
|
||||||
|
|
||||||
|
char **margv = malloc(sizeof(char *) * argc);
|
||||||
|
for (int i = 0; i < argc; i++) margv[i] = strdup(argv[i]);
|
||||||
|
create_actor(argc, margv);
|
||||||
|
|
||||||
|
SDL_CreateThread(crank_actor, "actor_runner", NULL);
|
||||||
|
|
||||||
|
signal(SIGINT, signal_handler);
|
||||||
|
signal(SIGTERM, signal_handler);
|
||||||
|
signal(SIGSEGV, signal_handler);
|
||||||
|
signal(SIGABRT, signal_handler);
|
||||||
|
atexit(exit_handler);
|
||||||
|
|
||||||
|
SDL_Event event;
|
||||||
|
while (SDL_WaitEvent(&event)) {
|
||||||
|
printf("Got event!\n");
|
||||||
|
if (event.type == SDL_EVENT_QUIT) return 0;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|||||||
@@ -4,20 +4,23 @@
|
|||||||
#include <SDL3/SDL.h>
|
#include <SDL3/SDL.h>
|
||||||
#include "quickjs.h"
|
#include "quickjs.h"
|
||||||
|
|
||||||
typedef JSValue (*MODULEFN)(JSContext *js);
|
|
||||||
|
|
||||||
#define STATE_VECTOR_LENGTH 624
|
#define STATE_VECTOR_LENGTH 624
|
||||||
#define STATE_VECTOR_M 397 /* changes to STATE_VECTOR_LENGTH also require changes to this */
|
#define STATE_VECTOR_M 397
|
||||||
|
|
||||||
|
#define ACTOR_IDLE 0
|
||||||
|
#define ACTOR_READY 1
|
||||||
|
#define ACTOR_RUNNING 2
|
||||||
|
#define ACTOR_EXHAUSTED 3
|
||||||
|
#define ACTOR_RECLAIMING 4
|
||||||
|
#define ACTOR_SLOW 5
|
||||||
|
|
||||||
|
typedef JSValue (*MODULEFN)(JSContext *js);
|
||||||
|
|
||||||
typedef struct tagMTRand {
|
typedef struct tagMTRand {
|
||||||
uint32_t mt[STATE_VECTOR_LENGTH];
|
uint32_t mt[STATE_VECTOR_LENGTH];
|
||||||
int32_t index;
|
int32_t index;
|
||||||
} MTRand;
|
} MTRand;
|
||||||
|
|
||||||
extern SDL_ThreadID main_thread;
|
|
||||||
|
|
||||||
extern SDL_TLSID prosperon_id;
|
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
const char *name;
|
const char *name;
|
||||||
MODULEFN fn;
|
MODULEFN fn;
|
||||||
@@ -33,40 +36,48 @@ struct message {
|
|||||||
size_t size;
|
size_t size;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define ACTOR_IDLE 0
|
|
||||||
#define ACTOR_READY 1
|
|
||||||
#define ACTOR_RUNNING 2
|
|
||||||
#define ACTOR_EXHAUSTED 3 // flagged when the actor is running GC
|
|
||||||
#define ACTOR_RECLAIMING 4
|
|
||||||
#define ACTOR_SLOW 5
|
|
||||||
|
|
||||||
typedef struct prosperon_rt {
|
typedef struct prosperon_rt {
|
||||||
cmdargs cmd; // args this actor was started with
|
cmdargs cmd;
|
||||||
JSContext *context; // The context this actor uses
|
JSContext *context;
|
||||||
char *id;
|
|
||||||
MTRand mrand;
|
|
||||||
JSValue cycle_fn;
|
JSValue cycle_fn;
|
||||||
JSValue idx_buffer;
|
JSValue idx_buffer;
|
||||||
JSValue on_exception;
|
JSValue on_exception;
|
||||||
JSValue message_handle;
|
JSValue message_handle;
|
||||||
JSValue unneeded;
|
JSValue unneeded;
|
||||||
double unneeded_secs;
|
struct { Uint32 key; JSValue value; } *timers;
|
||||||
int idx_count;
|
JSValue *events;
|
||||||
ModuleEntry *module_registry;
|
ModuleEntry *module_registry;
|
||||||
JSValue *js_swapchains;
|
JSValue *js_swapchains;
|
||||||
struct { Uint32 key; JSValue value; } *timers;
|
|
||||||
JSValue *events; // stack of events that need triggered on this actor
|
SDL_Mutex *mutex;
|
||||||
SDL_Mutex *mutex; // blocks access to modifying this actor
|
|
||||||
|
char *id;
|
||||||
|
MTRand mrand;
|
||||||
|
double unneeded_secs;
|
||||||
|
int idx_count;
|
||||||
|
|
||||||
struct message *messages;
|
struct message *messages;
|
||||||
int state; //
|
SDL_Mutex *msg_mutex;
|
||||||
Uint32 ar; // "actor removal" timer
|
int state;
|
||||||
|
Uint32 ar;
|
||||||
} prosperon_rt;
|
} prosperon_rt;
|
||||||
|
|
||||||
|
extern SDL_ThreadID main_thread;
|
||||||
|
extern SDL_TLSID prosperon_id;
|
||||||
|
|
||||||
|
prosperon_rt *create_actor(int argc, char **argv);
|
||||||
prosperon_rt *get_actor(char *id);
|
prosperon_rt *get_actor(char *id);
|
||||||
char *register_actor(char *id, prosperon_rt *actor);
|
char *register_actor(char *id, prosperon_rt *actor);
|
||||||
prosperon_rt *create_actor();
|
|
||||||
void actor_signal(prosperon_rt *actor);
|
void actor_signal(prosperon_rt *actor);
|
||||||
void actor_turn(prosperon_rt *actor);
|
|
||||||
void send_message(prosperon_rt *actor, struct message msg);
|
void send_message(prosperon_rt *actor, struct message msg);
|
||||||
|
void actor_turn(prosperon_rt *actor);
|
||||||
void actor_free(prosperon_rt *actor);
|
void actor_free(prosperon_rt *actor);
|
||||||
|
Uint32 actor_timer_cb(prosperon_rt *actor, SDL_TimerID id, Uint32 interval);
|
||||||
|
JSValue js_actor_delay(JSContext *js, JSValue self, int argc, JSValue *argv);
|
||||||
|
JSValue js_actor_removetimer(JSContext *js, JSValue self, int argc, JSValue *argv);
|
||||||
|
void script_startup(prosperon_rt *rt);
|
||||||
|
void script_evalf(JSContext *js, const char *format, ...);
|
||||||
|
JSValue script_eval(JSContext *js, const char *file, const char *script);
|
||||||
|
void uncaught_exception(JSContext *js, JSValue v);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -4,8 +4,7 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
|
#include "prosperon.h"
|
||||||
#include "script.h"
|
|
||||||
|
|
||||||
#define countof(a) (sizeof(a)/sizeof(*(a)))
|
#define countof(a) (sizeof(a)/sizeof(*(a)))
|
||||||
|
|
||||||
@@ -578,4 +577,4 @@ JSModuleDef *JS_INIT_MODULE(JSContext *ctx, const char *module_name)
|
|||||||
if (!m) return NULL;
|
if (!m) return NULL;
|
||||||
JS_AddModuleExport(ctx, m, "default");
|
JS_AddModuleExport(ctx, m, "default");
|
||||||
return m;
|
return m;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -100,19 +100,6 @@ static JSValue js_tracy_message(JSContext *js, JSValue self, int argc, JSValue *
|
|||||||
return JS_UNDEFINED;
|
return JS_UNDEFINED;
|
||||||
}
|
}
|
||||||
|
|
||||||
static JSValue js_tracy_thread_name(JSContext *js, JSValue self, int argc, JSValue *argv)
|
|
||||||
{
|
|
||||||
#ifdef TRACY_ON_DEMAND
|
|
||||||
if (!TracyCIsConnected)
|
|
||||||
return JS_UNDEFINED;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
const char *str = JS_ToCString(js, argv[0]);
|
|
||||||
TracyCSetThreadName(str);
|
|
||||||
JS_FreeCString(js,str);
|
|
||||||
return JS_UNDEFINED;
|
|
||||||
}
|
|
||||||
|
|
||||||
static JSValue js_tracy_zone_begin(JSContext *js, JSValue self, int argc, JSValue *argv)
|
static JSValue js_tracy_zone_begin(JSContext *js, JSValue self, int argc, JSValue *argv)
|
||||||
{
|
{
|
||||||
#ifdef TRACY_ON_DEMAND
|
#ifdef TRACY_ON_DEMAND
|
||||||
@@ -569,7 +556,6 @@ static const JSCFunctionListEntry js_tracy_funcs[] = {
|
|||||||
JS_CFUNC_DEF("gpu_init", 0, js_tracy_gpu_init),
|
JS_CFUNC_DEF("gpu_init", 0, js_tracy_gpu_init),
|
||||||
JS_CFUNC_DEF("gpu_sync", 0, js_tracy_gpu_sync),
|
JS_CFUNC_DEF("gpu_sync", 0, js_tracy_gpu_sync),
|
||||||
JS_CFUNC_DEF("end_frame", 0, js_tracy_frame_mark),
|
JS_CFUNC_DEF("end_frame", 0, js_tracy_frame_mark),
|
||||||
JS_CFUNC_DEF("thread_name", 1, js_tracy_thread_name),
|
|
||||||
JS_CFUNC_DEF("zone", 1, js_tracy_zone_begin),
|
JS_CFUNC_DEF("zone", 1, js_tracy_zone_begin),
|
||||||
JS_CFUNC_DEF("message", 1, js_tracy_message),
|
JS_CFUNC_DEF("message", 1, js_tracy_message),
|
||||||
JS_CFUNC_DEF("plot", 2, js_tracy_plot),
|
JS_CFUNC_DEF("plot", 2, js_tracy_plot),
|
||||||
|
|||||||
226
source/script.c
226
source/script.c
@@ -1,226 +0,0 @@
|
|||||||
#include "script.h"
|
|
||||||
#include "jsffi.h"
|
|
||||||
#include "stb_ds.h"
|
|
||||||
#include <inttypes.h>
|
|
||||||
#include <limits.h>
|
|
||||||
#include <sys/stat.h>
|
|
||||||
#include <errno.h>
|
|
||||||
#include <stdarg.h>
|
|
||||||
#include "jsffi.h"
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <assert.h>
|
|
||||||
#include "quickjs.h"
|
|
||||||
|
|
||||||
#include "prosperon.h"
|
|
||||||
|
|
||||||
#if defined(__APPLE__)
|
|
||||||
#include <malloc/malloc.h>
|
|
||||||
#elif defined(_WIN32)
|
|
||||||
#include <malloc.h>
|
|
||||||
#elif defined(__linux__) || defined(__GLIBC__)
|
|
||||||
#define _GNU_SOURCE
|
|
||||||
#include <malloc.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "physfs.h"
|
|
||||||
|
|
||||||
#define ENGINE "scripts/core/engine.js"
|
|
||||||
|
|
||||||
#ifdef TRACY_ENABLE
|
|
||||||
#include <tracy/TracyC.h>
|
|
||||||
|
|
||||||
#if defined(__APPLE__)
|
|
||||||
#define MALLOC_OVERHEAD 0
|
|
||||||
#else
|
|
||||||
#define MALLOC_OVERHEAD 8
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define likely(x) __builtin_expect(!!(x), 1)
|
|
||||||
#define unlikely(x) __builtin_expect(!!(x), 0)
|
|
||||||
|
|
||||||
/* default memory allocation functions with memory limitation */
|
|
||||||
static size_t js_tracy_malloc_usable_size(const void *ptr)
|
|
||||||
{
|
|
||||||
#if defined(__APPLE__)
|
|
||||||
return malloc_size(ptr);
|
|
||||||
#elif defined(_WIN32)
|
|
||||||
return _msize((void *)ptr);
|
|
||||||
#elif defined(EMSCRIPTEN)
|
|
||||||
return 0;
|
|
||||||
#elif defined(__linux__) || defined(__GLIBC__)
|
|
||||||
return malloc_usable_size((void *)ptr);
|
|
||||||
#else
|
|
||||||
/* change this to `return 0;` if compilation fails */
|
|
||||||
return malloc_usable_size((void *)ptr);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
static void *js_tracy_malloc(JSMallocState *s, size_t size)
|
|
||||||
{
|
|
||||||
void *ptr;
|
|
||||||
|
|
||||||
/* Do not allocate zero bytes: behavior is platform dependent */
|
|
||||||
assert(size != 0);
|
|
||||||
|
|
||||||
if (unlikely(s->malloc_size + size > s->malloc_limit))
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
ptr = malloc(size);
|
|
||||||
if (!ptr)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
s->malloc_count++;
|
|
||||||
s->malloc_size += js_tracy_malloc_usable_size(ptr) + MALLOC_OVERHEAD;
|
|
||||||
TracyCAllocN(ptr,js_tracy_malloc_usable_size(ptr) + MALLOC_OVERHEAD, "quickjs");
|
|
||||||
return ptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void js_tracy_free(JSMallocState *s, void *ptr)
|
|
||||||
{
|
|
||||||
if (!ptr)
|
|
||||||
return;
|
|
||||||
|
|
||||||
s->malloc_count--;
|
|
||||||
s->malloc_size -= js_tracy_malloc_usable_size(ptr) + MALLOC_OVERHEAD;
|
|
||||||
|
|
||||||
TracyCFreeN(ptr, "quickjs");
|
|
||||||
|
|
||||||
free(ptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void *js_tracy_realloc(JSMallocState *s, void *ptr, size_t size)
|
|
||||||
{
|
|
||||||
size_t old_size;
|
|
||||||
|
|
||||||
if (!ptr) {
|
|
||||||
if (size == 0)
|
|
||||||
return NULL;
|
|
||||||
return js_tracy_malloc(s, size);
|
|
||||||
}
|
|
||||||
old_size = js_tracy_malloc_usable_size(ptr);
|
|
||||||
if (size == 0) {
|
|
||||||
s->malloc_count--;
|
|
||||||
s->malloc_size -= old_size + MALLOC_OVERHEAD;
|
|
||||||
|
|
||||||
TracyCFreeN(ptr, "quickjs");
|
|
||||||
|
|
||||||
free(ptr);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
if (s->malloc_size + size - old_size > s->malloc_limit)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
TracyCFreeN(ptr, "quickjs");
|
|
||||||
|
|
||||||
ptr = realloc(ptr, size);
|
|
||||||
if (!ptr)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
s->malloc_size += js_tracy_malloc_usable_size(ptr) - old_size;
|
|
||||||
|
|
||||||
TracyCAllocN(ptr,js_tracy_malloc_usable_size(ptr) + MALLOC_OVERHEAD, "quickjs");
|
|
||||||
|
|
||||||
return ptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
static const JSMallocFunctions tracy_malloc_funcs = {
|
|
||||||
js_tracy_malloc,
|
|
||||||
js_tracy_free,
|
|
||||||
js_tracy_realloc,
|
|
||||||
js_tracy_malloc_usable_size
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// this function takes control of the program.
|
|
||||||
void script_startup(prosperon_rt *prt) {
|
|
||||||
JSRuntime *rt;
|
|
||||||
#ifdef TRACY_ENABLE
|
|
||||||
rt = JS_NewRuntime2(&tracy_malloc_funcs, NULL);
|
|
||||||
#else
|
|
||||||
rt = JS_NewRuntime();
|
|
||||||
#endif
|
|
||||||
JSContext *js = JS_NewContextRaw(rt);
|
|
||||||
JS_AddIntrinsicBaseObjects(js);
|
|
||||||
JS_AddIntrinsicEval(js);
|
|
||||||
JS_AddIntrinsicRegExp(js);
|
|
||||||
JS_AddIntrinsicJSON(js);
|
|
||||||
JS_AddIntrinsicMapSet(js);
|
|
||||||
JS_AddIntrinsicTypedArrays(js);
|
|
||||||
JS_AddIntrinsicBigInt(js);
|
|
||||||
JS_AddIntrinsicBigFloat(js);
|
|
||||||
JS_AddIntrinsicBigDecimal(js);
|
|
||||||
JS_AddIntrinsicOperators(js);
|
|
||||||
JS_EnableBignumExt(js, 1);
|
|
||||||
|
|
||||||
JS_SetContextOpaque(js, prt);
|
|
||||||
prt->context = js;
|
|
||||||
|
|
||||||
ffi_load(js);
|
|
||||||
|
|
||||||
PHYSFS_File *eng = PHYSFS_openRead(ENGINE);
|
|
||||||
if (!eng) {
|
|
||||||
printf("Could not open file! %s\n", PHYSFS_getErrorByCode(PHYSFS_getLastErrorCode()));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
PHYSFS_Stat stat;
|
|
||||||
PHYSFS_stat(ENGINE, &stat);
|
|
||||||
void *data = malloc(stat.filesize);
|
|
||||||
PHYSFS_readBytes(eng,data,stat.filesize);
|
|
||||||
PHYSFS_close(eng);
|
|
||||||
SDL_LockMutex(prt->mutex);
|
|
||||||
JSValue v = JS_Eval(js, data, strlen(data), ENGINE, JS_EVAL_FLAG_STRICT);
|
|
||||||
uncaught_exception(js,v);
|
|
||||||
SDL_UnlockMutex(prt->mutex);
|
|
||||||
}
|
|
||||||
|
|
||||||
void uncaught_exception(JSContext *js, JSValue v)
|
|
||||||
{
|
|
||||||
if (!JS_IsException(v)) {
|
|
||||||
JS_FreeValue(js,v);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
prosperon_rt *rt = JS_GetContextOpaque(js);
|
|
||||||
|
|
||||||
JSValue onexp = rt->on_exception;
|
|
||||||
|
|
||||||
if (!JS_IsUndefined(onexp)) {
|
|
||||||
JSValue ex = JS_GetException(js);
|
|
||||||
JSValue ret = JS_Call(js, onexp, JS_UNDEFINED, 1, &ex);
|
|
||||||
JS_FreeValue(js,ret);
|
|
||||||
JS_FreeValue(js,ex);
|
|
||||||
} else {
|
|
||||||
JSValue ex = JS_GetException(js);
|
|
||||||
const char *strex = JS_ToCString(js,ex);
|
|
||||||
JSValue stack = JS_GetPropertyStr(js,ex,"stack");
|
|
||||||
const char *st = JS_ToCString(js,stack);
|
|
||||||
printf("Unhandled exception: %s\n%s\n", strex, st);
|
|
||||||
JS_FreeValue(js,stack);
|
|
||||||
JS_FreeValue(js,ex);
|
|
||||||
JS_FreeCString(js,st);
|
|
||||||
JS_FreeCString(js,strex);
|
|
||||||
}
|
|
||||||
|
|
||||||
JS_FreeValue(js,v);
|
|
||||||
}
|
|
||||||
|
|
||||||
void script_evalf(JSContext *js, const char *format, ...)
|
|
||||||
{
|
|
||||||
JSValue obj;
|
|
||||||
va_list args;
|
|
||||||
va_start(args, format);
|
|
||||||
int len = vsnprintf(NULL, 0, format, args);
|
|
||||||
va_end(args);
|
|
||||||
|
|
||||||
char *eval = malloc(len+1);
|
|
||||||
va_start(args, format);
|
|
||||||
vsnprintf(eval, len+1, format, args);
|
|
||||||
va_end(args);
|
|
||||||
|
|
||||||
obj = JS_Eval(js, eval, len, "C eval", JS_EVAL_FLAG_STRICT);
|
|
||||||
free(eval);
|
|
||||||
|
|
||||||
uncaught_exception(js,obj);
|
|
||||||
}
|
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
#ifndef SCRIPT_H
|
|
||||||
#define SCRIPT_H
|
|
||||||
|
|
||||||
#include "quickjs.h"
|
|
||||||
#include <SDL3/SDL.h>
|
|
||||||
#include "prosperon.h"
|
|
||||||
|
|
||||||
void script_startup(prosperon_rt *rt);
|
|
||||||
|
|
||||||
void script_evalf(JSContext *js, const char *format, ...);
|
|
||||||
JSValue script_eval(JSContext *js, const char *file, const char *script);
|
|
||||||
void uncaught_exception(JSContext *js, JSValue v);
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -2,8 +2,8 @@
|
|||||||
#define SPRITE_H
|
#define SPRITE_H
|
||||||
|
|
||||||
#include "HandmadeMath.h"
|
#include "HandmadeMath.h"
|
||||||
#include "script.h"
|
|
||||||
#include "render.h"
|
#include "render.h"
|
||||||
|
#include "quickjs.h"
|
||||||
|
|
||||||
struct sprite{
|
struct sprite{
|
||||||
rect affine;
|
rect affine;
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
#include "transform.h"
|
#include "transform.h"
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include "script.h"
|
|
||||||
#include "stb_ds.h"
|
#include "stb_ds.h"
|
||||||
|
|
||||||
static transform **dirties;
|
static transform **dirties;
|
||||||
|
|||||||
@@ -13,3 +13,5 @@ $_.start(e => {
|
|||||||
$_.stop(e.actor)
|
$_.stop(e.actor)
|
||||||
}
|
}
|
||||||
}, "tests/underling.js");
|
}, "tests/underling.js");
|
||||||
|
|
||||||
|
console.log("OVELRING BOTTOM");
|
||||||
|
|||||||
@@ -3,3 +3,5 @@ var os = use('os')
|
|||||||
$_.receiver(e => {
|
$_.receiver(e => {
|
||||||
console.log(`got message: ${json.encode(e)}`)
|
console.log(`got message: ${json.encode(e)}`)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
console.log("UNDERLING BOTTOM");
|
||||||
|
|||||||
Reference in New Issue
Block a user