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:
parent
7f0643f9c0
commit
cb2dfc696d
@ -63,6 +63,8 @@ static int _object_to_headers(JSContext* context, JSValue object, const char** h
|
|||||||
}
|
}
|
||||||
headers[count * 2 + 0] = JS_ToCString(context, key);
|
headers[count * 2 + 0] = JS_ToCString(context, key);
|
||||||
headers[count * 2 + 1] = JS_ToCString(context, key_value);
|
headers[count * 2 + 1] = JS_ToCString(context, key_value);
|
||||||
|
JS_FreeValue(context, key);
|
||||||
|
JS_FreeValue(context, key_value);
|
||||||
}
|
}
|
||||||
for (uint32_t i = 0; i < plen; ++i)
|
for (uint32_t i = 0; i < plen; ++i)
|
||||||
{
|
{
|
||||||
@ -315,11 +317,18 @@ static JSValue _httpd_websocket_upgrade(JSContext* context, JSValueConst this_va
|
|||||||
headers[headers_count * 2 + 1] = key;
|
headers[headers_count * 2 + 1] = key;
|
||||||
headers_count++;
|
headers_count++;
|
||||||
}
|
}
|
||||||
headers_count += _object_to_headers(context, argv[1], headers + headers_count * 2, tf_countof(headers) - headers_count * 2);
|
int js_headers_count = _object_to_headers(context, argv[1], headers + headers_count * 2, tf_countof(headers) - headers_count * 2);
|
||||||
|
headers_count += js_headers_count;
|
||||||
|
|
||||||
tf_http_request_websocket_upgrade(request);
|
tf_http_request_websocket_upgrade(request);
|
||||||
tf_http_respond(request, 101, headers, headers_count, NULL, 0);
|
tf_http_respond(request, 101, headers, headers_count, NULL, 0);
|
||||||
|
|
||||||
|
for (int i = headers_count - js_headers_count; i < headers_count * 2; i++)
|
||||||
|
{
|
||||||
|
JS_FreeCString(context, headers[i * 2 + 0]);
|
||||||
|
JS_FreeCString(context, headers[i * 2 + 1]);
|
||||||
|
}
|
||||||
|
|
||||||
request->on_message = _httpd_message_callback;
|
request->on_message = _httpd_message_callback;
|
||||||
request->on_close = _httpd_websocket_close_callback;
|
request->on_close = _httpd_websocket_close_callback;
|
||||||
request->context = context;
|
request->context = context;
|
||||||
|
@ -856,6 +856,7 @@ static void _tf_ssb_sqlAsync_after_work(uv_work_t* work, int status)
|
|||||||
JS_FreeValue(context, sql_work->promise[0]);
|
JS_FreeValue(context, sql_work->promise[0]);
|
||||||
JS_FreeValue(context, sql_work->promise[1]);
|
JS_FreeValue(context, sql_work->promise[1]);
|
||||||
JS_FreeValue(context, sql_work->callback);
|
JS_FreeValue(context, sql_work->callback);
|
||||||
|
JS_FreeCString(context, sql_work->query);
|
||||||
_tf_ssb_sqlAsync_destroy(sql_work);
|
_tf_ssb_sqlAsync_destroy(sql_work);
|
||||||
tf_trace_end(trace);
|
tf_trace_end(trace);
|
||||||
}
|
}
|
||||||
|
118
src/task.c
118
src/task.c
@ -83,6 +83,17 @@ typedef struct _hitch_t
|
|||||||
uint64_t duration_ns;
|
uint64_t duration_ns;
|
||||||
} hitch_t;
|
} 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
|
typedef struct _tf_task_t
|
||||||
{
|
{
|
||||||
taskid_t _nextTask;
|
taskid_t _nextTask;
|
||||||
@ -145,6 +156,8 @@ typedef struct _tf_task_t
|
|||||||
promise_stack_t* _promise_stacks;
|
promise_stack_t* _promise_stacks;
|
||||||
int _promise_stack_count;
|
int _promise_stack_count;
|
||||||
|
|
||||||
|
timeout_t* timeouts;
|
||||||
|
|
||||||
hitch_t hitches[32];
|
hitch_t hitches[32];
|
||||||
} tf_task_t;
|
} 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_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_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_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 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);
|
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 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_idle(uv_idle_t* idle);
|
||||||
static void _tf_task_run_jobs_prepare(uv_prepare_t* prepare);
|
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
|
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, "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, "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, "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);
|
JS_FreeValue(context, global);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1834,6 +1851,15 @@ void tf_task_destroy(tf_task_t* task)
|
|||||||
|
|
||||||
JS_FreeValue(task->_context, task->_loadedFiles);
|
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)
|
if (task->_ssb)
|
||||||
{
|
{
|
||||||
tf_ssb_destroy(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(task->_promise_stacks);
|
||||||
tf_free((void*)task->_path);
|
tf_free((void*)task->_path);
|
||||||
|
bool was_trusted = task->_trusted;
|
||||||
tf_free(task);
|
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)
|
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;
|
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;
|
||||||
|
}
|
||||||
|
@ -244,60 +244,6 @@ bool tf_util_report_error(JSContext* context, JSValue value)
|
|||||||
return is_error;
|
return is_error;
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef struct _timeout_t {
|
|
||||||
uv_timer_t _timer;
|
|
||||||
tf_task_t* _task;
|
|
||||||
JSValue _callback;
|
|
||||||
} timeout_t;
|
|
||||||
|
|
||||||
static void _handle_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));
|
|
||||||
uv_close((uv_handle_t*)handle, _handle_closed);
|
|
||||||
}
|
|
||||||
|
|
||||||
static JSValue _util_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 },
|
|
||||||
};
|
|
||||||
|
|
||||||
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);
|
|
||||||
tf_free(timeout);
|
|
||||||
}
|
|
||||||
return JS_NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
static JSValue _util_parseHttpRequest(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv)
|
static JSValue _util_parseHttpRequest(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv)
|
||||||
{
|
{
|
||||||
JSValue result = JS_UNDEFINED;
|
JSValue result = JS_UNDEFINED;
|
||||||
@ -491,7 +437,6 @@ void tf_util_register(JSContext* context)
|
|||||||
JS_SetPropertyStr(context, global, "bip39Words", JS_NewCFunction(context, _util_bip39_words, "bip39Words", 1));
|
JS_SetPropertyStr(context, global, "bip39Words", JS_NewCFunction(context, _util_bip39_words, "bip39Words", 1));
|
||||||
JS_SetPropertyStr(context, global, "bip39Bytes", JS_NewCFunction(context, _util_bip39_bytes, "bip39Bytes", 1));
|
JS_SetPropertyStr(context, global, "bip39Bytes", JS_NewCFunction(context, _util_bip39_bytes, "bip39Bytes", 1));
|
||||||
JS_SetPropertyStr(context, global, "print", JS_NewCFunction(context, _util_print, "print", 1));
|
JS_SetPropertyStr(context, global, "print", JS_NewCFunction(context, _util_print, "print", 1));
|
||||||
JS_SetPropertyStr(context, global, "setTimeout", JS_NewCFunction(context, _util_setTimeout, "setTimeout", 2));
|
|
||||||
JS_SetPropertyStr(context, global, "parseHttpRequest", JS_NewCFunction(context, _util_parseHttpRequest, "parseHttpRequest", 2));
|
JS_SetPropertyStr(context, global, "parseHttpRequest", JS_NewCFunction(context, _util_parseHttpRequest, "parseHttpRequest", 2));
|
||||||
JS_SetPropertyStr(context, global, "parseHttpResponse", JS_NewCFunction(context, _util_parseHttpResponse, "parseHttpResponse", 2));
|
JS_SetPropertyStr(context, global, "parseHttpResponse", JS_NewCFunction(context, _util_parseHttpResponse, "parseHttpResponse", 2));
|
||||||
JS_SetPropertyStr(context, global, "sha1Digest", JS_NewCFunction(context, _util_sha1_digest, "sha1Digest", 1));
|
JS_SetPropertyStr(context, global, "sha1Digest", JS_NewCFunction(context, _util_sha1_digest, "sha1Digest", 1));
|
||||||
|
Loading…
Reference in New Issue
Block a user