Skip to content

Commit 396ff45

Browse files
Use try-lock to append a job to the worker queue
This change uses `withLockIfAvailable` to append a job to the worker queue not to use `atomic.wait` on the main thread, which is rejected by some browser engines.
1 parent 502da6e commit 396ff45

File tree

1 file changed

+29
-26
lines changed

1 file changed

+29
-26
lines changed

Diff for: Sources/JavaScriptEventLoop/WebWorkerTaskExecutor.swift

+29-26
Original file line numberDiff line numberDiff line change
@@ -138,34 +138,37 @@ public final class WebWorkerTaskExecutor: TaskExecutor {
138138
/// Enqueue a job to the worker.
139139
func enqueue(_ job: UnownedJob) {
140140
statsIncrement(\.enqueuedJobs)
141-
jobQueue.withLock { queue in
142-
queue.append(job)
143-
144-
// Wake up the worker to process a job.
145-
switch state.exchange(.running, ordering: .sequentiallyConsistent) {
146-
case .idle:
147-
if Self.currentThread === self {
148-
// Enqueueing a new job to the current worker thread, but it's idle now.
149-
// This is usually the case when a continuation is resumed by JS events
150-
// like `setTimeout` or `addEventListener`.
151-
// We can run the job and subsequently spawned jobs immediately.
152-
// JSPromise.resolve(JSValue.undefined).then { _ in
153-
_ = JSObject.global.queueMicrotask!(JSOneshotClosure { _ in
154-
self.run()
155-
return JSValue.undefined
156-
})
157-
} else {
158-
let tid = self.tid.load(ordering: .sequentiallyConsistent)
159-
swjs_wake_up_worker_thread(tid)
141+
var locked: Bool
142+
repeat {
143+
let result: Void? = jobQueue.withLockIfAvailable { queue in
144+
queue.append(job)
145+
// Wake up the worker to process a job.
146+
switch state.exchange(.running, ordering: .sequentiallyConsistent) {
147+
case .idle:
148+
if Self.currentThread === self {
149+
// Enqueueing a new job to the current worker thread, but it's idle now.
150+
// This is usually the case when a continuation is resumed by JS events
151+
// like `setTimeout` or `addEventListener`.
152+
// We can run the job and subsequently spawned jobs immediately.
153+
// JSPromise.resolve(JSValue.undefined).then { _ in
154+
_ = JSObject.global.queueMicrotask!(JSOneshotClosure { _ in
155+
self.run()
156+
return JSValue.undefined
157+
})
158+
} else {
159+
let tid = self.tid.load(ordering: .sequentiallyConsistent)
160+
swjs_wake_up_worker_thread(tid)
161+
}
162+
case .running:
163+
// The worker is already running, no need to wake up.
164+
break
165+
case .terminated:
166+
// Will not wake up the worker because it's already terminated.
167+
break
160168
}
161-
case .running:
162-
// The worker is already running, no need to wake up.
163-
break
164-
case .terminated:
165-
// Will not wake up the worker because it's already terminated.
166-
break
167169
}
168-
}
170+
locked = result != nil
171+
} while !locked
169172
}
170173

171174
func scheduleNextRun() {

0 commit comments

Comments
 (0)