Conversation
| JSJobEntry *e; | ||
| int i; | ||
|
|
||
| while (!list_empty(&rt->job_list)) { |
There was a problem hiding this comment.
Why not splice the list, set an empty one, and then operate on the spliced list to avoid the risk of any finalizers from ever calling enqueue job?
There was a problem hiding this comment.
Here is code you can use to move rt->job_list into a temporary list_head:
diff --git a/list.h b/list.h
index b8dd716..779af5d 100644
--- a/list.h
+++ b/list.h
@@ -86,6 +86,27 @@ static inline int list_empty(struct list_head *el)
return el->next == el;
}
+static inline void list_split(struct list_head *src,
+ struct list_head *el,
+ struct list_head *dst)
+{
+ dst->prev = src->prev;
+ dst->prev->next = dst;
+ dst->next = el;
+ src->prev = el->prev;
+ src->prev->next = src;
+ el->prev = dst;
+}
+
+static inline void list_move(struct list_head *src, struct list_head *dst)
+{
+ if (list_empty(src)) {
+ init_list_head(dst);
+ } else {
+ list_split(src, src->next, dst);
+ }
+}
+
#define list_for_each(el, head) \
for(el = (head)->next; el != (head); el = el->next)
There was a problem hiding this comment.
Thanks, I've used list_move / list_split to detach the queue before releasing any arguments. Jobs enqueued by native finalizers now remain pending, and the returned count covers only the original queue. I've updated the header contract and added tests for singleton and multi-entry queues, argument finalization, and executing the surviving jobs afterward. The API tests pass, including under ASan.
| JS_EXTERN int JS_EnqueueJob(JSContext *ctx, JSJobFunc *job_func, | ||
| int argc, JSValueConst *argv); | ||
|
|
||
| /* Discard all queued jobs without executing their callbacks. Releases the |
There was a problem hiding this comment.
Sound a bit like a loaded gun, any chance of making it safer? I left a suggestion above.
Keep owned job arguments as JSValue and borrow them when enqueuing. This avoids struct-to-struct casts rejected by MSVC while preserving JS_CHECK_JSVALUE compatibility.
|
Thinking about this more...
That "or destroying the runtime" won't fly. Canceling jobs at the wrong time leaves the runtime in an irreparable state. Example: dynamic import jobs, e.g., With that in mind, I don't think this API is a good addition. It won't work for what you want to use it, plus, it's very footgunny. |
|
Thanks, you were right about the lifetime issue. I reproduced it with queued jobs and pending top-level-await modules, where clearing the queue alone does not restore existing asynchronous state. I opened #1751 to address the underlying job, context, and module lifetimes separately. Once that behavior is settled, I’ll revisit the scope and contract of this PR. |
Hosts cancelling an evaluation need to release queued jobs without running more callbacks or destroying the runtime.
Add
JS_DiscardPendingJobs, returning the discarded count and releasing each job's retained arguments and queue entry. Document runtime ownership, exclusive access, finalizer restrictions, and the effect on promises.API tests cover empty and repeated discard, retained-value cleanup, callbacks remaining uncalled, and subsequent jobs executing in the same runtime.
Validation: API tests (also under AddressSanitizer on both the current upstream and rquickjs 0.14 engine baselines), JavaScript tests (115 on the compatible engine baseline and 116 on current upstream), C/C++ header checks, and strict value-type checks on macOS. The strict check uses
CC='clang -Wno-unused-command-line-argument'for Apple's clang.Dependent bindings: DelSkayn/rquickjs#768.