diff options
-rw-r--r-- | AUTHORS | 1 | ||||
-rw-r--r-- | src/library_browser.js | 21 | ||||
-rw-r--r-- | system/include/emscripten/emscripten.h | 9 | ||||
-rw-r--r-- | tests/test_browser.py | 4 | ||||
-rw-r--r-- | tests/worker_api_3_main.cpp | 44 | ||||
-rw-r--r-- | tests/worker_api_3_worker.cpp | 25 |
6 files changed, 98 insertions, 6 deletions
@@ -118,3 +118,4 @@ a license to everyone to use it as detailed in LICENSE.) * Alexandre Perrot <alexandre.perrot@gmail.com> * Emerson José Silveira da Costa <emerson.costa@gmail.com> * Jari Vetoniemi <mailroxas@gmail.com> +* Dave Nicponski <dave.nicponski@gmail.com> diff --git a/src/library_browser.js b/src/library_browser.js index 458a8dd2..9261a2cf 100644 --- a/src/library_browser.js +++ b/src/library_browser.js @@ -1,7 +1,6 @@ //"use strict"; // Utilities for browser environments - mergeInto(LibraryManager.library, { $Browser__deps: ['$PATH'], $Browser__postset: 'Module["requestFullScreen"] = function Module_requestFullScreen(lockPointer, resizeCanvas) { Browser.requestFullScreen(lockPointer, resizeCanvas) };\n' + // exports @@ -918,8 +917,11 @@ mergeInto(LibraryManager.library, { var callbackId = msg.data['callbackId']; var callbackInfo = info.callbacks[callbackId]; if (!callbackInfo) return; // no callback or callback removed meanwhile - info.awaited--; - info.callbacks[callbackId] = null; // TODO: reuse callbackIds, compress this + // Don't trash our callback state if we expect additional calls. + if (msg.data['finalResponse']) { + info.awaited--; + info.callbacks[callbackId] = null; // TODO: reuse callbackIds, compress this + } var data = msg.data['data']; if (data) { if (!data.byteLength) data = new Uint8Array(data); @@ -964,12 +966,23 @@ mergeInto(LibraryManager.library, { }); }, + emscripten_worker_respond_provisionally: function(data, size) { + if (!inWorkerCall) throw 'not in worker call!'; + if (workerResponded) throw 'already responded with final response!'; + postMessage({ + 'callbackId': workerCallbackId, + 'finalResponse': false, + 'data': data ? new Uint8Array({{{ makeHEAPView('U8', 'data', 'data + size') }}}) : 0 // XXX copy to a new typed array as a workaround for chrome bug 169705 + }); + }, + emscripten_worker_respond: function(data, size) { if (!inWorkerCall) throw 'not in worker call!'; - if (workerResponded) throw 'already responded!'; + if (workerResponded) throw 'already responded with final response!'; workerResponded = true; postMessage({ 'callbackId': workerCallbackId, + 'finalResponse': true, 'data': data ? new Uint8Array({{{ makeHEAPView('U8', 'data', 'data + size') }}}) : 0 // XXX copy to a new typed array as a workaround for chrome bug 169705 }); }, diff --git a/system/include/emscripten/emscripten.h b/system/include/emscripten/emscripten.h index b6e6307b..918059f2 100644 --- a/system/include/emscripten/emscripten.h +++ b/system/include/emscripten/emscripten.h @@ -377,10 +377,15 @@ void emscripten_destroy_worker(worker_handle worker); void emscripten_call_worker(worker_handle worker, const char *funcname, char *data, int size, void (*callback)(char *, int, void*), void *arg); /* - * Sends a response when in a worker call. Should only be - * called once in each call. + * Sends a response when in a worker call. Both functions post a message + * back to the thread which called the worker. The _respond_provisionally + * variant can be invoked multiple times, which will queue up messages to + * be posted to the worker's creator. Eventually, the _respond variant can + * be invoked, which will disallow further messages and free framework + * resources previously allocated for this worker call. */ void emscripten_worker_respond(char *data, int size); +void emscripten_worker_respond_provisionally(char *data, int size); /* * Checks how many responses are being waited for from a worker. This diff --git a/tests/test_browser.py b/tests/test_browser.py index eed18a3d..3b9d6ebb 100644 --- a/tests/test_browser.py +++ b/tests/test_browser.py @@ -1678,6 +1678,10 @@ keydown(100);keyup(100); // trigger the end Popen([PYTHON, EMCC, path_from_root('tests', 'worker_api_2_worker.cpp'), '-o', 'worker.js', '-s', 'BUILD_AS_WORKER=1', '-O2', '--minify', '0', '-s', 'EXPORTED_FUNCTIONS=["_one", "_two", "_three", "_four"]']).communicate() self.btest('worker_api_2_main.cpp', args=['-O2', '--minify', '0'], expected='11') + def test_worker_api_3(self): + Popen([PYTHON, EMCC, path_from_root('tests', 'worker_api_3_worker.cpp'), '-o', 'worker.js', '-s', 'BUILD_AS_WORKER=1', '-s', 'EXPORTED_FUNCTIONS=["_one"]']).communicate() + self.btest('worker_api_3_main.cpp', expected='5') + def test_emscripten_async_wget2(self): self.btest('http.cpp', expected='0', args=['-I' + path_from_root('tests')]) diff --git a/tests/worker_api_3_main.cpp b/tests/worker_api_3_main.cpp new file mode 100644 index 00000000..595f99b9 --- /dev/null +++ b/tests/worker_api_3_main.cpp @@ -0,0 +1,44 @@ +#include <stdio.h> +#include <assert.h> +#include <emscripten.h> + +int w1; + +bool sawCalls[] = { false, false, false, false }; + +void c1(char *data, int size, void *arg) { + assert((int)arg == 97); + assert(size >= sizeof(int)); + + int *x = (int*)data; + printf("c1: %d\n", x[0]); + + if (*x >= 0 && *x < 4) { + // Calls should have happened in order. + sawCalls[*x] = true; // Note the call with current param was made + for (int i = 0; i < *x - 1; ++i) { + if (!sawCalls[i]) { + // If we were called out of order, fail this and all following calls. + sawCalls[*x] = false; + break; + } + } + } else { + assert(*x == 4); + // This is the last call. All prior calls should have occurred. + int result = 1; // Final call occurred. + for (int i = 0; i < 4; ++i) + if (sawCalls[i]) result++; + REPORT_RESULT(); + } +} + +int main() { + w1 = emscripten_create_worker("worker.js"); + + int x[1] = { 0 }; + emscripten_call_worker(w1, "one", (char*)x, sizeof(x), c1, (void*)97); + + return 0; +} + diff --git a/tests/worker_api_3_worker.cpp b/tests/worker_api_3_worker.cpp new file mode 100644 index 00000000..db14377a --- /dev/null +++ b/tests/worker_api_3_worker.cpp @@ -0,0 +1,25 @@ +#include <assert.h> +#include <emscripten.h> + +extern "C" { + +// Respond with 0, 1, 2, 3 each with finalResponse=false, and 4 with +// finalResponse=true. +void one(char *data, int size) { + int *x = (int*)data; + + if (*x == 0) { + // Respond 0, 1, 2, 3 + for (int i = 0; i < 4; ++i) { + *x = i; + emscripten_worker_respond_provisionally(data, size); + } + } + + // Respond 4 + *x = 4; + emscripten_worker_respond(data, size); +} + +} + |