Fixed a few more good leaks. Now there are just some unclean shutdown issues.

git-svn-id: https://www.unprompted.com/svn/projects/tildefriends/trunk@4803 ed5197a5-7fde-0310-b194-c3ffbd925b24
This commit is contained in:
2024-01-27 18:26:01 +00:00
parent 7f0643f9c0
commit cb2dfc696d
4 changed files with 129 additions and 56 deletions

View File

@ -83,6 +83,17 @@ typedef struct _hitch_t
uint64_t duration_ns;
} hitch_t;
typedef struct _timeout_t timeout_t;
typedef struct _timeout_t
{
timeout_t* previous;
timeout_t* next;
uv_timer_t _timer;
tf_task_t* _task;
JSValue _callback;
} timeout_t;
typedef struct _tf_task_t
{
taskid_t _nextTask;
@ -145,6 +156,8 @@ typedef struct _tf_task_t
promise_stack_t* _promise_stacks;
int _promise_stack_count;
timeout_t* timeouts;
hitch_t hitches[32];
} tf_task_t;
@ -185,6 +198,7 @@ static JSValue _tf_task_get_parent(JSContext* context, JSValueConst this_val, in
static JSValue _tf_task_exit(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv);
static JSValue _tf_task_getStats(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv);
static JSValue _tf_task_getFile(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv);
static JSValue _tf_task_setTimeout(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv);
static promise_t* _tf_task_find_promise(tf_task_t* task, promiseid_t id);
static void _tf_task_sendPromiseResolve(tf_task_t* from, tf_taskstub_t* to, promiseid_t promise, JSValue result);
@ -197,6 +211,8 @@ static void _tf_task_release_export(tf_taskstub_t* stub, exportid_t exportId);
static bool _tf_task_run_jobs(tf_task_t* task);
static void _tf_task_run_jobs_idle(uv_idle_t* idle);
static void _tf_task_run_jobs_prepare(uv_prepare_t* prepare);
static void _timeout_unlink(tf_task_t* task, timeout_t* timeout);
static void _timeout_closed(uv_handle_t* handle);
typedef struct _import_record_t
{
@ -1762,6 +1778,7 @@ void tf_task_activate(tf_task_t* task)
JS_SetPropertyStr(context, global, "version", JS_NewCFunction(context, _tf_task_version, "version", 0));
JS_SetPropertyStr(context, global, "platform", JS_NewCFunction(context, _tf_task_platform, "platform", 0));
JS_SetPropertyStr(context, global, "getFile", JS_NewCFunction(context, _tf_task_getFile, "getFile", 1));
JS_SetPropertyStr(context, global, "setTimeout", JS_NewCFunction(context, _tf_task_setTimeout, "setTimeout", 2));
JS_FreeValue(context, global);
}
@ -1834,6 +1851,15 @@ void tf_task_destroy(tf_task_t* task)
JS_FreeValue(task->_context, task->_loadedFiles);
while (task->timeouts)
{
timeout_t* timeout = task->timeouts;
JS_FreeValue(task->_context, timeout->_callback);
timeout->_callback = JS_UNDEFINED;
_timeout_unlink(task, timeout);
uv_close((uv_handle_t*)&timeout->_timer, _timeout_closed);
}
if (task->_ssb)
{
tf_ssb_destroy(task->_ssb);
@ -1906,7 +1932,12 @@ void tf_task_destroy(tf_task_t* task)
}
tf_free(task->_promise_stacks);
tf_free((void*)task->_path);
bool was_trusted = task->_trusted;
tf_free(task);
if (was_trusted)
{
tf_printf("Goodbye.");
}
}
JSValue tf_task_add_import(tf_task_t* task, taskid_t stub_id, exportid_t export_id)
@ -2015,3 +2046,90 @@ const char* tf_task_get_name(tf_task_t* task)
{
return task->_scriptName;
}
static void _timeout_link(tf_task_t* task, timeout_t* timeout)
{
assert(!timeout->previous);
assert(!timeout->next);
timeout->previous = task->timeouts ? task->timeouts->previous : timeout;
timeout->next = task->timeouts ? task->timeouts: timeout;
if (task->timeouts)
{
task->timeouts->previous = timeout;
if (task->timeouts->next == task->timeouts)
{
task->timeouts->next = timeout;
}
}
task->timeouts = timeout;
}
static void _timeout_unlink(tf_task_t* task, timeout_t* timeout)
{
assert(timeout->previous);
assert(timeout->next);
if (timeout->next == timeout && timeout->previous == timeout)
{
task->timeouts = NULL;
}
else
{
timeout->next->previous = timeout->previous;
timeout->previous->next = timeout->next;
if (task->timeouts == timeout)
{
task->timeouts = timeout->next;
}
}
}
static void _timeout_closed(uv_handle_t* handle)
{
timeout_t* timeout = handle->data;
tf_free(timeout);
}
static void _util_timeoutCallback(uv_timer_t* handle)
{
timeout_t* timeout = handle->data;
tf_trace_begin(tf_task_get_trace(timeout->_task), "_util_timeoutCallback");
JSContext* context = tf_task_get_context(timeout->_task);
JSValue result = JS_Call(
context,
timeout->_callback,
JS_NULL,
0,
NULL);
tf_util_report_error(context, result);
JS_FreeValue(context, result);
JS_FreeValue(context, timeout->_callback);
tf_trace_end(tf_task_get_trace(timeout->_task));
_timeout_unlink(timeout->_task, timeout);
uv_close((uv_handle_t*)handle, _timeout_closed);
}
static JSValue _tf_task_setTimeout(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv)
{
tf_task_t* task = JS_GetContextOpaque(context);
timeout_t* timeout = tf_malloc(sizeof(timeout_t));
*timeout = (timeout_t)
{
._task = task,
._callback = JS_DupValue(context, argv[0]),
._timer = { .data = timeout },
};
_timeout_link(task, timeout);
uv_timer_init(tf_task_get_loop(task), &timeout->_timer);
int64_t duration;
JS_ToInt64(context, &duration, argv[1]);
if (uv_timer_start(&timeout->_timer, _util_timeoutCallback, duration, 0) != 0)
{
JS_FreeValue(context, timeout->_callback);
_timeout_unlink(task, timeout);
tf_free(timeout);
}
return JS_NULL;
}