From bf4711a01d7a3cd9bb8e2bdf86fa653bdea356d5 Mon Sep 17 00:00:00 2001 From: Joseph Cloutier Date: Fri, 9 Aug 2024 15:58:48 -0400 Subject: [PATCH] Avoid sending `JobData` back to the main thread. The main thread can easily look these up by ID, and in HTML5, sending the full `JobData` can cause errors. --- src/lime/app/Future.hx | 6 ---- src/lime/system/ThreadPool.hx | 36 ++++++++++++----------- src/lime/system/WorkOutput.hx | 54 ++++++++++------------------------- 3 files changed, 35 insertions(+), 61 deletions(-) diff --git a/src/lime/app/Future.hx b/src/lime/app/Future.hx index 2af97182d..780a243b0 100644 --- a/src/lime/app/Future.hx +++ b/src/lime/app/Future.hx @@ -416,17 +416,11 @@ import lime.utils.Log; var result = bundle.work.dispatch(bundle.state); if (result != null || bundle.legacyCode) { - #if (lime_threads && html5) - bundle.work.makePortable(); - #end output.sendComplete(result); } } catch (e:Dynamic) { - #if (lime_threads && html5) - bundle.work.makePortable(); - #end output.sendError(e); } } diff --git a/src/lime/system/ThreadPool.hx b/src/lime/system/ThreadPool.hx index 4a3bae7ef..f997abe69 100644 --- a/src/lime/system/ThreadPool.hx +++ b/src/lime/system/ThreadPool.hx @@ -245,12 +245,12 @@ class ThreadPool extends WorkOutput var thread:Thread = __activeThreads[job.id]; if (idleThreads < minThreads) { - thread.sendMessage(new ThreadEvent(WORK, null, null)); + thread.sendMessage({event: CANCEL}); __idleThreads.push(thread); } else { - thread.sendMessage(new ThreadEvent(EXIT, null, null)); + thread.sendMessage({event: EXIT}); } } #end @@ -270,10 +270,10 @@ class ThreadPool extends WorkOutput __activeJobs.clear(); #if lime_threads - // Cancel idle threads if there are more than the minimum. + // Exit idle threads if there are more than the minimum. while (idleThreads > minThreads) { - __idleThreads.pop().sendMessage(new ThreadEvent(EXIT, null, null)); + __idleThreads.pop().sendMessage({event: EXIT}); } #end @@ -310,7 +310,7 @@ class ThreadPool extends WorkOutput var thread:Thread = __activeThreads[data.id]; if (thread != null) { - thread.sendMessage(new ThreadEvent(WORK, null, null)); + thread.sendMessage({event: CANCEL}); __activeThreads.remove(data.id); __idleThreads.push(thread); } @@ -395,7 +395,7 @@ class ThreadPool extends WorkOutput { event = Thread.readMessage(true); } - while (!#if (haxe_ver >= 4.2) Std.isOfType #else Std.is #end (event, ThreadEvent)); + while (event == null || !Reflect.hasField(event, "event")); output.resetJobProgress(); } @@ -409,7 +409,7 @@ class ThreadPool extends WorkOutput return; } - if (event.event != WORK || event.job == null) + if (event.event != WORK || !#if (haxe_ver >= 4.2) Std.isOfType #else Std.is #end (event.job, JobData)) { // Go idle. event = null; @@ -440,7 +440,7 @@ class ThreadPool extends WorkOutput // Work is done; wait for more. event = interruption; } - else if(#if (haxe_ver >= 4.2) Std.isOfType #else Std.is #end (interruption, ThreadEvent)) + else if(Reflect.hasField(interruption, "event")) { // Work on the new job. event = interruption; @@ -494,7 +494,7 @@ class ThreadPool extends WorkOutput var thread:Thread = __idleThreads.isEmpty() ? createThread(__executeThread) : __idleThreads.pop(); __activeThreads[job.id] = thread; - thread.sendMessage(new ThreadEvent(WORK, null, job)); + thread.sendMessage({event: WORK, job: job}); } #end } @@ -539,15 +539,19 @@ class ThreadPool extends WorkOutput var threadEvent:ThreadEvent; while ((threadEvent = __jobOutput.pop(false)) != null) { - if (!__activeJobs.exists(threadEvent.job)) + if (threadEvent.jobID != null) { - // Ignore events from canceled jobs. - continue; + activeJob = __activeJobs.getByID(threadEvent.jobID); + } + else + { + activeJob = threadEvent.job; } - // Get by ID because in HTML5, the object will have been cloned, - // which will interfere with attempts to test equality. - activeJob = __activeJobs.getByID(threadEvent.job.id); + if (activeJob == null || !__activeJobs.exists(activeJob)) + { + continue; + } if (mode == MULTI_THREADED) { @@ -582,7 +586,7 @@ class ThreadPool extends WorkOutput if (currentThreads > maxThreads || __jobQueue.length == 0 && currentThreads > minThreads) { - thread.sendMessage(new ThreadEvent(EXIT, null, null)); + thread.sendMessage({event: EXIT}); } else { diff --git a/src/lime/system/WorkOutput.hx b/src/lime/system/WorkOutput.hx index 433fad10e..a35b5fb71 100644 --- a/src/lime/system/WorkOutput.hx +++ b/src/lime/system/WorkOutput.hx @@ -105,12 +105,11 @@ class WorkOutput #if (lime_threads && html5) if (mode == MULTI_THREADED) { - activeJob.doWork.makePortable(); - Thread.returnMessage(new ThreadEvent(COMPLETE, message, activeJob), transferList); + Thread.returnMessage({event: COMPLETE, message: message, jobID: activeJob.id}, transferList); } else #end - __jobOutput.add(new ThreadEvent(COMPLETE, message, activeJob)); + __jobOutput.add({event: COMPLETE, message: message, jobID: activeJob.id}); } } @@ -130,12 +129,11 @@ class WorkOutput #if (lime_threads && html5) if (mode == MULTI_THREADED) { - activeJob.doWork.makePortable(); - Thread.returnMessage(new ThreadEvent(ERROR, message, activeJob), transferList); + Thread.returnMessage({event: ERROR, message: message, jobID: activeJob.id}, transferList); } else #end - __jobOutput.add(new ThreadEvent(ERROR, message, activeJob)); + __jobOutput.add({event: ERROR, message: message, jobID: activeJob.id}); } } @@ -153,12 +151,11 @@ class WorkOutput #if (lime_threads && html5) if (mode == MULTI_THREADED) { - activeJob.doWork.makePortable(); - Thread.returnMessage(new ThreadEvent(PROGRESS, message, activeJob), transferList); + Thread.returnMessage({event: PROGRESS, message: message, jobID: activeJob.id}, transferList); } else #end - __jobOutput.add(new ThreadEvent(PROGRESS, message, activeJob)); + __jobOutput.add({event: PROGRESS, message: message, jobID: activeJob.id}); } } @@ -343,43 +340,22 @@ class JobData #if haxe4 enum #else @:enum #end abstract ThreadEventType(String) { - /** - Sent by the background thread, indicating completion. - **/ + // Events sent from a worker thread to the main thread var COMPLETE = "COMPLETE"; - /** - Sent by the background thread, indicating failure. - **/ var ERROR = "ERROR"; - /** - Sent by the background thread. - **/ var PROGRESS = "PROGRESS"; - /** - Sent by the main thread, indicating that the provided job should begin - in place of any ongoing job. If `state == null`, the existing job will - stop and the thread will go idle. (To run a job with no argument, set - `state = {}` instead.) - **/ + + // Commands sent from the main thread to a worker thread var WORK = "WORK"; - /** - Sent by the main thread to shut down a thread. - **/ + var CANCEL = "CANCEL"; var EXIT = "EXIT"; } -class ThreadEvent -{ - public var event(default, null):ThreadEventType; - public var message(default, null):State; - public var job(default, null):JobData; - - public inline function new(event:ThreadEventType, message:State, job:JobData) - { - this.event = event; - this.message = message; - this.job = job; - } +typedef ThreadEvent = { + var event:ThreadEventType; + @:optional var message:Dynamic; + @:optional var job:JobData; + @:optional var jobID:Int; } class JSAsync