make tracy work for multilpe contexts
Some checks failed
Build and Deploy / build-windows (CLANG64) (push) Has been cancelled
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
Some checks failed
Build and Deploy / build-windows (CLANG64) (push) Has been cancelled
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
This commit is contained in:
@@ -22,6 +22,13 @@ prosperon.dispatch = function(type, data) {
|
||||
}
|
||||
|
||||
var os = use_embed('os')
|
||||
var tracy = use_embed('tracy')
|
||||
|
||||
os.trace = true;
|
||||
|
||||
if (os.trace)
|
||||
tracy.level(1);
|
||||
|
||||
var js = use_embed('js')
|
||||
|
||||
prosperon.on('exit', _ => {
|
||||
@@ -58,7 +65,7 @@ Object.defineProperty(Function.prototype, "hashify", {
|
||||
})
|
||||
|
||||
var io = use_embed('io')
|
||||
var tracy = use_embed('tracy')
|
||||
|
||||
|
||||
var RESPATH = 'scripts/modules/resources.js'
|
||||
var canonical = io.realdir(RESPATH) + 'resources.js'
|
||||
@@ -285,27 +292,27 @@ var time = use('time')
|
||||
|
||||
function parse_file(content, file) {
|
||||
if (!content) return {}
|
||||
var parts = content.split(/\n\s*---\s*\n/)
|
||||
if (parts.length === 1) {
|
||||
var part = parts[0]
|
||||
if (!/^\s*---\s*$/m.test(content)) {
|
||||
var part = content.trim()
|
||||
if (part.match(/return\s+[^;]+;?\s*$/))
|
||||
return { module: part }
|
||||
return { program: part }
|
||||
}
|
||||
var parts = content.split(/\n\s*---\s*\n/)
|
||||
var module = parts[0]
|
||||
if (!/\breturn\b/.test(module))
|
||||
throw new Error(`Malformed file: ${file}. Module section must end with a return statement.`);
|
||||
throw new Error(`Malformed file: ${file}. Module section must end with a return statement.`)
|
||||
|
||||
try {
|
||||
new Function(module)()
|
||||
} catch (e) {
|
||||
throw new Error(`Malformed file: ${file}. Module section must end with a return statement.\n` + e.message);
|
||||
throw new Error(`Malformed file: ${file}. Module section must end with a return statement.\n` + e.message)
|
||||
}
|
||||
|
||||
var pad = '\n'.repeat(module.split('\n').length+4)
|
||||
var pad = '\n'.repeat(module.split('\n').length + 4)
|
||||
return {
|
||||
module,
|
||||
program: pad+parts[1]
|
||||
program: pad + parts[1]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -755,8 +762,8 @@ var timers = []
|
||||
var timer_id = 0
|
||||
|
||||
$_.delay = function(fn, seconds) {
|
||||
timers[timer_id++] = {seconds, fn}
|
||||
return function() { delete timers[timer_id] }
|
||||
var id = os.os.addtimer(prosperon.id, fn, seconds);
|
||||
return function() { os.removetimer(id); }
|
||||
}
|
||||
$_.delay[prosperon.DOC] = "used to schedule the invocation of a function..."
|
||||
|
||||
@@ -836,6 +843,8 @@ cmd.process(prosperon.argv)
|
||||
if (!prosperon.args.id) prosperon.id = util.guid()
|
||||
else prosperon.id = prosperon.args.id
|
||||
|
||||
tracy.thread_name(prosperon.id)
|
||||
|
||||
$_.__ACTORDATA__.id = prosperon.id
|
||||
|
||||
if (prosperon.args.overling) overling = { __ACTORDATA__: {id: prosperon.args.overling} }
|
||||
@@ -923,14 +932,14 @@ function handle_message(msg) {
|
||||
unneeded_timer = $_.delay(unneeded_fn, unneeded_time)
|
||||
}
|
||||
|
||||
var hang = 0.01
|
||||
var hang = 0.1
|
||||
var last_t = os.now()
|
||||
|
||||
var doexit = false
|
||||
while (!doexit) {
|
||||
if (portal) portal.service(handle_host, hang)
|
||||
if (contactor) contactor.service(handle_host, hang)
|
||||
os.mailbox_service(prosperon.id, handle_local)
|
||||
os.mailbox_service(prosperon.id, handle_local, hang)
|
||||
var elapsed = os.now() - last_t
|
||||
last_t = os.now()
|
||||
for (var i in timers) {
|
||||
|
||||
131
source/jsffi.c
131
source/jsffi.c
@@ -70,6 +70,7 @@ typedef struct rtree rtree;
|
||||
int randombytes(void *buf, size_t n);
|
||||
|
||||
static Uint32 timer_cb_event;
|
||||
static int trace = 0;
|
||||
|
||||
#ifdef __APPLE__
|
||||
#include <Accelerate/Accelerate.h>
|
||||
@@ -7093,37 +7094,50 @@ typedef struct {
|
||||
int create_new_runtime(cmdargs *data)
|
||||
{
|
||||
script_startup(data->argc, data->argv);
|
||||
|
||||
printf("THREAD IS STOPPING\n");
|
||||
for (int i = 0; i < data->argc; i++) free(data->argv[i]);
|
||||
free(data->argv);
|
||||
free(data);
|
||||
return 0;
|
||||
}
|
||||
|
||||
JSC_CCALL(os_createthread,
|
||||
cmdargs cmd;
|
||||
cmd.argc = JS_ArrayLength(js,argv[0]);
|
||||
cmd.argv = (char **)calloc(cmd.argc, sizeof(char *));
|
||||
// Convert JS array elements to C strings
|
||||
for (int i = 0; i < cmd.argc; i++) {
|
||||
cmdargs *cmd = malloc(sizeof(cmdargs));
|
||||
if (!cmd) return JS_ThrowInternalError(js, "Out of memory");
|
||||
cmd->argc = JS_ArrayLength(js, argv[0]);
|
||||
cmd->argv = (char **)calloc(cmd->argc, sizeof(char *));
|
||||
if (!cmd->argv) {
|
||||
free(cmd);
|
||||
return JS_ThrowInternalError(js, "Out of memory");
|
||||
}
|
||||
for (int i = 0; i < cmd->argc; i++) {
|
||||
JSValue val = JS_GetPropertyUint32(js, argv[0], i);
|
||||
if (JS_IsException(val)) {
|
||||
free(cmd.argv);
|
||||
for (int j = 0; j < i; j++) free(cmd->argv[j]);
|
||||
free(cmd->argv);
|
||||
free(cmd);
|
||||
return val;
|
||||
}
|
||||
|
||||
const char *str = JS_ToCString(js, val);
|
||||
if (!str) {
|
||||
free(cmd.argv);
|
||||
for (int j = 0; j < i; j++) free(cmd->argv[j]);
|
||||
free(cmd->argv);
|
||||
free(cmd);
|
||||
JS_FreeValue(js, val);
|
||||
return JS_ThrowInternalError(js, "Could not convert argument to string");
|
||||
}
|
||||
|
||||
cmd.argv[i] = strdup(str); // Make a copy of the string
|
||||
cmd->argv[i] = strdup(str);
|
||||
JS_FreeCString(js, str);
|
||||
JS_FreeValue(js, val);
|
||||
}
|
||||
SDL_Thread *thread = SDL_CreateThread(create_new_runtime, "newrt", &cmd);
|
||||
if (!thread) return JS_ThrowInternalError(js, "Could not create a new thread: %s", SDL_GetError());
|
||||
SDL_Thread *thread = SDL_CreateThread(create_new_runtime, "newrt", cmd);
|
||||
if (!thread) {
|
||||
for (int i = 0; i < cmd->argc; i++) free(cmd->argv[i]);
|
||||
free(cmd->argv);
|
||||
free(cmd);
|
||||
return JS_ThrowInternalError(js, "Could not create a new thread: %s", SDL_GetError());
|
||||
}
|
||||
SDL_DetachThread(thread);
|
||||
return JS_UNDEFINED;
|
||||
)
|
||||
|
||||
struct message {
|
||||
@@ -7133,6 +7147,7 @@ struct message {
|
||||
|
||||
typedef struct mailbox {
|
||||
SDL_Mutex *mutex;
|
||||
SDL_Condition *cond;
|
||||
struct message *messages;
|
||||
} mailbox;
|
||||
|
||||
@@ -7141,29 +7156,28 @@ static SDL_Mutex *mailboxes_mutex = NULL;
|
||||
|
||||
JSC_CCALL(os_mailbox_push,
|
||||
if (argc < 2) return JS_ThrowInternalError(js, "Need an actor and a message");
|
||||
if (!JS_IsArrayBuffer(js, argv[1])) return JS_ThrowInternalError(js, "Object to push into the mailbox must be an array buffer.");
|
||||
if (!JS_IsArrayBuffer(js, argv[1])) return JS_ThrowInternalError(js, "Object to push must be an array buffer");
|
||||
|
||||
const char *id = JS_ToCString(js, argv[0]);
|
||||
int mailbox_index = shgeti(mailboxes, id);
|
||||
JS_FreeCString(js, id);
|
||||
|
||||
if (mailbox_index == -1)
|
||||
return JS_ThrowInternalError(js, "No mailbox found for given ID");
|
||||
if (mailbox_index == -1) return JS_ThrowInternalError(js, "No mailbox found for given ID");
|
||||
|
||||
size_t size;
|
||||
uint8_t *buf = JS_GetArrayBuffer(js, &size, argv[1]);
|
||||
|
||||
if (!buf) return JS_ThrowInternalError(js, "Could not get data from arraybuffer.");
|
||||
if (!buf) return JS_ThrowInternalError(js, "Could not get data from arraybuffer");
|
||||
|
||||
void *data = js_malloc_rt(JS_GetRuntime(js), size);
|
||||
if (!data) return JS_ThrowInternalError(js, "Memory allocation failed.");
|
||||
if (!data) return JS_ThrowInternalError(js, "Memory allocation failed");
|
||||
|
||||
memcpy(data,buf,size);
|
||||
memcpy(data, buf, size);
|
||||
|
||||
mailbox *mb = &mailboxes[mailbox_index].value;
|
||||
SDL_LockMutex(mb->mutex);
|
||||
struct message msg = {data, size};
|
||||
arrput(mb->messages, msg);
|
||||
SDL_SignalCondition(mb->cond); // Signal waiting threads
|
||||
SDL_UnlockMutex(mb->mutex);
|
||||
)
|
||||
|
||||
@@ -7174,6 +7188,7 @@ void js_dofree(JSRuntime *rt, void *opaque, void *ptr)
|
||||
|
||||
JSC_CCALL(os_mailbox_service,
|
||||
if (!JS_IsFunction(js, argv[1])) return JS_ThrowInternalError(js, "Arg 2 must be a function");
|
||||
if (argc < 3 || !JS_IsNumber(argv[2])) return JS_ThrowInternalError(js, "Arg 3 must be a number (timeout in seconds)");
|
||||
|
||||
const char *id = JS_ToCString(js, argv[0]);
|
||||
int mb_index = shgeti(mailboxes, id);
|
||||
@@ -7181,9 +7196,25 @@ JSC_CCALL(os_mailbox_service,
|
||||
|
||||
if (mb_index == -1) return JS_ThrowInternalError(js, "No mailbox found for given ID");
|
||||
|
||||
// Get timeout in seconds and convert to milliseconds
|
||||
int32_t timeout_seconds;
|
||||
if (JS_ToInt32(js, &timeout_seconds, argv[2]) != 0) return JS_ThrowInternalError(js, "Invalid timeout value");
|
||||
int timeout_ms = timeout_seconds * 1000; // Convert to milliseconds for SDL
|
||||
|
||||
mailbox *mb = &mailboxes[mb_index].value;
|
||||
struct message *temp = NULL;
|
||||
SDL_LockMutex(mb->mutex);
|
||||
|
||||
// Wait for messages if the mailbox is empty
|
||||
while (arrlen(mb->messages) == 0) {
|
||||
bool signaled = SDL_WaitConditionTimeout(mb->cond, mb->mutex, timeout_ms);
|
||||
if (!signaled) { // Timeout occurred
|
||||
SDL_UnlockMutex(mb->mutex);
|
||||
return JS_UNDEFINED;
|
||||
}
|
||||
}
|
||||
|
||||
// Process messages after wait
|
||||
int count = arrlen(mb->messages);
|
||||
if (count > 0) {
|
||||
arrsetlen(temp, count);
|
||||
@@ -7200,7 +7231,7 @@ JSC_CCALL(os_mailbox_service,
|
||||
JSValue arg = JS_NewArrayBuffer(js, temp[i].data, temp[i].size, js_dofree, NULL, 0);
|
||||
JSValue call = JS_Call(js, fn, JS_UNDEFINED, 1, &arg);
|
||||
uncaught_exception(js, call);
|
||||
JS_FreeValue(js,arg);
|
||||
JS_FreeValue(js, arg);
|
||||
}
|
||||
|
||||
arrfree(temp);
|
||||
@@ -7218,6 +7249,7 @@ JSC_CCALL(os_mailbox_start,
|
||||
const char *id = JS_ToCString(js, argv[0]);
|
||||
mailbox mb;
|
||||
mb.mutex = SDL_CreateMutex();
|
||||
mb.cond = SDL_CreateCondition();
|
||||
mb.messages = NULL;
|
||||
if (!mailboxes_mutex) mailboxes_mutex = SDL_CreateMutex();
|
||||
|
||||
@@ -7245,6 +7277,7 @@ JSC_CCALL(os_mailbox_destroy,
|
||||
SDL_UnlockMutex(mb->mutex);
|
||||
|
||||
SDL_DestroyMutex(mb->mutex);
|
||||
SDL_DestroyCondition(mb->cond);
|
||||
|
||||
SDL_LockMutex(mailboxes_mutex);
|
||||
shdel(mailboxes, id);
|
||||
@@ -7273,16 +7306,68 @@ JSC_CCALL(os_waitevent,
|
||||
return JS_UNDEFINED;
|
||||
)
|
||||
|
||||
JSValue js_os_get_trace(JSContext *js, JSValue self)
|
||||
{
|
||||
return JS_NewBool(js, trace);
|
||||
}
|
||||
|
||||
JSValue js_os_set_trace(JSContext *js, JSValue self, JSValue value)
|
||||
{
|
||||
trace = JS_ToBool(js, value);
|
||||
return JS_UNDEFINED;
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
char *timer_id; // Unique timer identifier
|
||||
char *mailbox_id; // Mailbox to send the message to
|
||||
} timer_data;
|
||||
|
||||
typedef struct {
|
||||
char *timer_id; // Timer ID
|
||||
JSValue fn; // Function to invoke
|
||||
} timer_mapping;
|
||||
|
||||
static timer_mapping *timers = NULL; // Dynamic array of timer mappings
|
||||
static SDL_Mutex *timers_mutex = NULL; // Mutex for thread-safe access to timers
|
||||
|
||||
void init_timers(void)
|
||||
{
|
||||
if (!timers_mutex) timers_mutex = SDL_CreateMutex();
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
JSValue fn;
|
||||
const char *id;
|
||||
} timer_cb;
|
||||
|
||||
JSC_CCALL(os_addtimer,
|
||||
|
||||
Uint64 ns = js2number(js,argv[1])*1000000000.0;
|
||||
timer_cb cb;
|
||||
cb.fn = JS_DupValue(js,argv[0]);
|
||||
cb.id = JS_ToCString(js,argv[2]);
|
||||
|
||||
|
||||
)
|
||||
|
||||
JSC_CCALL(os_removetimer,
|
||||
|
||||
)
|
||||
|
||||
static const JSCFunctionListEntry js_os_funcs[] = {
|
||||
MIST_FUNC_DEF(os, make_transform, 0),
|
||||
MIST_FUNC_DEF(os, clean_transforms, 0),
|
||||
|
||||
MIST_FUNC_DEF(os, addtimer, 3),
|
||||
MIST_FUNC_DEF(os, removetimer, 1),
|
||||
|
||||
MIST_FUNC_DEF(os, platform, 0),
|
||||
MIST_FUNC_DEF(os, arch, 0),
|
||||
MIST_FUNC_DEF(os, totalmem, 0),
|
||||
MIST_FUNC_DEF(os, freemem, 0),
|
||||
MIST_FUNC_DEF(os, hostname, 0),
|
||||
MIST_FUNC_DEF(os, version, 0),
|
||||
JS_CGETSET_DEF("trace", js_os_get_trace, js_os_set_trace),
|
||||
|
||||
MIST_FUNC_DEF(os, kill, 1),
|
||||
MIST_FUNC_DEF(os, exit, 1),
|
||||
@@ -8005,8 +8090,6 @@ void ffi_load(JSContext *js, int argc, char **argv) {
|
||||
QJSCLASSPREP_FUNCS(datastream);
|
||||
QJSCLASSPREP_FUNCS(timer);
|
||||
|
||||
|
||||
|
||||
timer_cb_event = SDL_RegisterEvents(1);
|
||||
|
||||
JS_SetPropertyStr(js, globalThis, "use_dyn", JS_NewCFunction(js,js_os_use_dyn,"use_dyn", 1));
|
||||
|
||||
@@ -109,6 +109,5 @@ int main(int argc, char **argv) {
|
||||
}
|
||||
|
||||
script_startup(argc, argv); // runs engine.js
|
||||
printf("MADE IT HERE AT BOTTOM OF MAIN\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -496,26 +496,57 @@ static JSValue js_tracy_image(JSContext *js, JSValue self, int argc, JSValue *ar
|
||||
|
||||
#endif
|
||||
|
||||
static TracyCZoneCtx *tracy_stack;
|
||||
// Wrapper struct to keep the array pointer stable
|
||||
typedef struct {
|
||||
TracyCZoneCtx *arr; // stb_ds dynamic array
|
||||
} tracy_stack_t;
|
||||
|
||||
// Global TLS ID for the Tracy stack
|
||||
static SDL_TLSID tracy_stack_id = {0};
|
||||
|
||||
// Cleanup function for the wrapper struct
|
||||
static void tracy_cleanup_stack(void *value)
|
||||
{
|
||||
tracy_stack_t *stack = value;
|
||||
if (stack) {
|
||||
arrfree(stack->arr);
|
||||
free(stack);
|
||||
}
|
||||
}
|
||||
|
||||
// Get or initialize the thread-local Tracy stack
|
||||
static tracy_stack_t *get_tracy_stack(void)
|
||||
{
|
||||
tracy_stack_t *stack = SDL_GetTLS(&tracy_stack_id);
|
||||
if (!stack) {
|
||||
stack = malloc(sizeof(tracy_stack_t));
|
||||
stack->arr = NULL; // stb_ds starts with NULL
|
||||
arrsetcap(stack->arr, 5); // Initial capacity
|
||||
SDL_SetTLS(&tracy_stack_id, stack, tracy_cleanup_stack);
|
||||
}
|
||||
return stack;
|
||||
}
|
||||
|
||||
void tracy_call_hook(JSContext *js, JSValue fn)
|
||||
{
|
||||
tracy_stack_t *stack = get_tracy_stack();
|
||||
js_debug debug;
|
||||
js_debug_info(js,fn,&debug);
|
||||
js_debug_info(js, fn, &debug);
|
||||
|
||||
uint64_t srcloc;
|
||||
srcloc = ___tracy_alloc_srcloc(debug.line, debug.source, debug.srclen, debug.name, strlen(debug.name), (int)debug.source);
|
||||
uint64_t srcloc = ___tracy_alloc_srcloc(debug.line, debug.filename, strlen(debug.filename), debug.name, strlen(debug.name), debug.unique);
|
||||
arrput(stack->arr, ___tracy_emit_zone_begin_alloc(srcloc, 1));
|
||||
|
||||
arrput(tracy_stack, ___tracy_emit_zone_begin_alloc(srcloc,1));
|
||||
free_js_debug_info(js, &debug);
|
||||
}
|
||||
|
||||
void tracy_end_hook(JSContext *js, JSValue fn)
|
||||
{
|
||||
if (arrlen(tracy_stack) >0)
|
||||
___tracy_emit_zone_end(arrpop(tracy_stack));
|
||||
tracy_stack_t *stack = get_tracy_stack();
|
||||
if (arrlen(stack->arr) > 0)
|
||||
___tracy_emit_zone_end(arrpop(stack->arr));
|
||||
}
|
||||
|
||||
JSValue js_tracy_level(JSContext *js, JSValue selff, int argc, JSValue *argv)
|
||||
JSValue js_tracy_level(JSContext *js, JSValue self, int argc, JSValue *argv)
|
||||
{
|
||||
int32_t level;
|
||||
JS_ToInt32(js,&level, argv[0]);
|
||||
|
||||
@@ -188,7 +188,6 @@ void script_stop(JSContext *js)
|
||||
|
||||
free(prt);
|
||||
|
||||
printf("STOPPING CONTEXT %p\n", js);
|
||||
JSValue *onexp = SDL_GetTLS(&on_exception);
|
||||
JS_FreeValue(js,*onexp);
|
||||
JSRuntime *rt = JS_GetRuntime(js);
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
var os = use('os')
|
||||
|
||||
$_.stop()
|
||||
|
||||
$_.start(e => {
|
||||
switch(e.type) {
|
||||
case "actor_started":
|
||||
@@ -13,6 +11,5 @@ $_.start(e => {
|
||||
$_.couple(e.actor)
|
||||
|
||||
$_.stop(e.actor)
|
||||
$_.stop()
|
||||
}
|
||||
}, "tests/underling.js");
|
||||
|
||||
Reference in New Issue
Block a user