diff --git a/Firmware/Makefile b/Firmware/Makefile index 1682f6a0..fca96493 100644 --- a/Firmware/Makefile +++ b/Firmware/Makefile @@ -50,6 +50,8 @@ libfibre-all: cp /tmp/libfibre-build/libfibre-macos-x86.dylib ../tools/odrive/pyfibre/fibre/ docker run -it -v "`pwd`/fibre-cpp":/build -v /tmp/libfibre-build:/build/build -w /build fibre-compiler configs/windows-amd64.config cp /tmp/libfibre-build/libfibre-windows-amd64.dll ../tools/odrive/pyfibre/fibre/ + docker run -it -v "`pwd`/fibre-cpp":/build -v /tmp/libfibre-build:/build/build -w /build fibre-compiler configs/wasm.config + cp /tmp/libfibre-build/libfibre-wasm.* ../GUI/fibre-js/ clean: -rm -fR .dep $(BUILD_DIR) diff --git a/Firmware/fibre-cpp/legacy_protocol.cpp b/Firmware/fibre-cpp/legacy_protocol.cpp index ca6f78da..7afd1371 100644 --- a/Firmware/fibre-cpp/legacy_protocol.cpp +++ b/Firmware/fibre-cpp/legacy_protocol.cpp @@ -9,6 +9,7 @@ #include #include #include +#include DEFINE_LOG_TOPIC(LEGACY_PROTOCOL); USE_LOG_TOPIC(LEGACY_PROTOCOL); @@ -218,16 +219,8 @@ void LegacyProtocolPacketBased::start_endpoint_operation(uint16_t endpoint_id, c if (tx_handle_) { FIBRE_LOG(D) << "Endpoint operation already in progress. Enqueuing this one."; - // A TX operation is already in progress - if (pending_operation_.has_value()) { - // Previous endpoint operation was not yet sent. We don't support - // enqueuing multiple endpoint operations while the first didn't send yet. - FIBRE_LOG(E) << "previous endpoint operation still not sent"; - callback.invoke_and_clear({kStreamError, tx_buf.begin(), rx_buf.begin()}); - } else { - // Control is returned to start_endpoint_operation once TX completes - pending_operation_ = op; - } + // A TX operation is already in progress. Enqueue this one. + pending_operations_.push_back(op); return; } @@ -266,20 +259,24 @@ void LegacyProtocolPacketBased::cancel_endpoint_operation(EndpointOperationHandl const uint8_t* tx_end = nullptr; uint8_t* rx_end = nullptr; - if (pending_operation_.has_value() && pending_operation_->seqno == seqno) { - callback = pending_operation_->callback; - tx_end = pending_operation_->tx_buf.begin(); - rx_end = pending_operation_->rx_buf.begin(); - pending_operation_ = std::nullopt; + auto it0 = std::find_if(pending_operations_.begin(), pending_operations_.end(), [&](EndpointOperation& op) { + return op.seqno == seqno; + }); + + if (it0 != pending_operations_.end()) { + callback = it0->callback; + tx_end = it0->tx_buf.begin(); + rx_end = it0->rx_buf.begin(); + pending_operations_.erase(it0); } - auto it = expected_acks_.find(seqno); + auto it1 = expected_acks_.find(seqno); - if (it != expected_acks_.end()) { - callback = it->second.callback; - tx_end = it->second.tx_buf.begin(); - rx_end = it->second.rx_buf.begin(); - expected_acks_.erase(it); + if (it1 != expected_acks_.end()) { + callback = it1->second.callback; + tx_end = it1->second.tx_buf.begin(); + rx_end = it1->second.rx_buf.begin(); + expected_acks_.erase(it1); } if (transmitting_op_ == handle) { @@ -378,11 +375,11 @@ void LegacyProtocolPacketBased::on_write_finished(WriteResult result) { #endif #if FIBRE_ENABLE_CLIENT - if (pending_operation_.has_value()) { + if (pending_operations_.size() > 0) { // There is a write operation pending from the client side (i.e. an // outgoing remote endpoint operation). - EndpointOperation op = *pending_operation_; - pending_operation_ = std::nullopt; + EndpointOperation op = pending_operations_[0]; + pending_operations_.erase(pending_operations_.begin()); start_endpoint_operation(op); if (transmitting_op_) { return; @@ -530,10 +527,10 @@ void LegacyProtocolPacketBased::on_rx_tx_closed(StreamStatus status) { #if FIBRE_ENABLE_CLIENT // Cancel pending endpoint operation - if (pending_operation_.has_value()) { - pending_operation_->callback.invoke_and_clear({status, pending_operation_->tx_buf.begin(), pending_operation_->rx_buf.begin()}); - pending_operation_ = std::nullopt; + for (auto& op: pending_operations_) { + op.callback.invoke_and_clear({status, op.tx_buf.begin(), op.rx_buf.begin()}); } + pending_operations_.clear(); // Cancel all ongoing endpoint operations for (auto& item: expected_acks_) { diff --git a/Firmware/fibre-cpp/legacy_protocol.hpp b/Firmware/fibre-cpp/legacy_protocol.hpp index 1644f5d9..962f4123 100644 --- a/Firmware/fibre-cpp/legacy_protocol.hpp +++ b/Firmware/fibre-cpp/legacy_protocol.hpp @@ -7,6 +7,7 @@ #include "legacy_object_client.hpp" #include #include +#include #endif namespace fibre { @@ -135,7 +136,7 @@ private: void start_endpoint_operation(EndpointOperation op); uint16_t outbound_seq_no_ = 0; - std::optional pending_operation_ = std::nullopt; // operation that is waiting for TX + std::vector pending_operations_; // operations that are waiting for TX EndpointOperationHandle transmitting_op_ = 0; // operation that is in TX std::unordered_map expected_acks_; // operations that are waiting for RX #endif diff --git a/Firmware/fibre-cpp/libfibre.cpp b/Firmware/fibre-cpp/libfibre.cpp index f7907508..c92f00b2 100644 --- a/Firmware/fibre-cpp/libfibre.cpp +++ b/Firmware/fibre-cpp/libfibre.cpp @@ -56,7 +56,7 @@ fibre::ChannelDiscoveryContext* from_c(LibFibreChannelDiscoveryCtx* ptr) { } -static const struct LibFibreVersion libfibre_version = { 0, 1, 3 }; +static const struct LibFibreVersion libfibre_version = { 0, 1, 4 }; class FIBRE_PRIVATE ExternalEventLoop final : public fibre::EventLoop { public: diff --git a/GUI/fibre-js/libfibre-wasm.js b/GUI/fibre-js/libfibre-wasm.js index d67f4a62..5ee8284a 100644 --- a/GUI/fibre-js/libfibre-wasm.js +++ b/GUI/fibre-js/libfibre-wasm.js @@ -216,7 +216,7 @@ if (ENVIRONMENT_IS_WEB || ENVIRONMENT_IS_WORKER) { - read_ = function shell_read(url) { + read_ = function(url) { var xhr = new XMLHttpRequest(); xhr.open('GET', url, false); xhr.send(null); @@ -224,7 +224,7 @@ if (ENVIRONMENT_IS_WEB || ENVIRONMENT_IS_WORKER) { }; if (ENVIRONMENT_IS_WORKER) { - readBinary = function readBinary(url) { + readBinary = function(url) { var xhr = new XMLHttpRequest(); xhr.open('GET', url, false); xhr.responseType = 'arraybuffer'; @@ -233,11 +233,11 @@ if (ENVIRONMENT_IS_WEB || ENVIRONMENT_IS_WORKER) { }; } - readAsync = function readAsync(url, onload, onerror) { + readAsync = function(url, onload, onerror) { var xhr = new XMLHttpRequest(); xhr.open('GET', url, true); xhr.responseType = 'arraybuffer'; - xhr.onload = function xhr_onload() { + xhr.onload = function() { if (xhr.status == 200 || (xhr.status == 0 && xhr.response)) { // file URLs can return 0 onload(xhr.response); return; @@ -278,8 +278,11 @@ moduleOverrides = null; // to the proper local x. This has two benefits: first, we only emit it if it is // expected to arrive, and second, by using a local everywhere else that can be // minified. + if (Module['arguments']) arguments_ = Module['arguments']; + if (Module['thisProgram']) thisProgram = Module['thisProgram']; + if (Module['quit']) quit_ = Module['quit']; // perform assertions in shell.js after we set up out() and err(), as otherwise if an assertion fails it cannot print the message @@ -526,9 +529,9 @@ var getTempRet0 = function() { // An online HTML version (which may be of a different version of Emscripten) // is up at http://kripken.github.io/emscripten-site/docs/api_reference/preamble.js.html - -var wasmBinary;if (Module['wasmBinary']) wasmBinary = Module['wasmBinary']; -var noExitRuntime;if (Module['noExitRuntime']) noExitRuntime = Module['noExitRuntime']; +var wasmBinary; +if (Module['wasmBinary']) wasmBinary = Module['wasmBinary']; +var noExitRuntime = Module['noExitRuntime'] || true; if (typeof WebAssembly !== 'object') { @@ -549,13 +552,13 @@ function setValue(ptr, value, type, noSafe) { type = type || 'i8'; if (type.charAt(type.length-1) === '*') type = 'i32'; // pointers are 32-bit switch(type) { - case 'i1': HEAP8[((ptr)>>0)]=value; break; - case 'i8': HEAP8[((ptr)>>0)]=value; break; - case 'i16': HEAP16[((ptr)>>1)]=value; break; - case 'i32': HEAP32[((ptr)>>2)]=value; break; - case 'i64': (tempI64 = [value>>>0,(tempDouble=value,(+(Math.abs(tempDouble))) >= 1.0 ? (tempDouble > 0.0 ? ((Math.min((+(Math.floor((tempDouble)/4294967296.0))), 4294967295.0))|0)>>>0 : (~~((+(Math.ceil((tempDouble - +(((~~(tempDouble)))>>>0))/4294967296.0)))))>>>0) : 0)],HEAP32[((ptr)>>2)]=tempI64[0],HEAP32[(((ptr)+(4))>>2)]=tempI64[1]); break; - case 'float': HEAPF32[((ptr)>>2)]=value; break; - case 'double': HEAPF64[((ptr)>>3)]=value; break; + case 'i1': HEAP8[((ptr)>>0)] = value; break; + case 'i8': HEAP8[((ptr)>>0)] = value; break; + case 'i16': HEAP16[((ptr)>>1)] = value; break; + case 'i32': HEAP32[((ptr)>>2)] = value; break; + case 'i64': (tempI64 = [value>>>0,(tempDouble=value,(+(Math.abs(tempDouble))) >= 1.0 ? (tempDouble > 0.0 ? ((Math.min((+(Math.floor((tempDouble)/4294967296.0))), 4294967295.0))|0)>>>0 : (~~((+(Math.ceil((tempDouble - +(((~~(tempDouble)))>>>0))/4294967296.0)))))>>>0) : 0)],HEAP32[((ptr)>>2)] = tempI64[0],HEAP32[(((ptr)+(4))>>2)] = tempI64[1]); break; + case 'float': HEAPF32[((ptr)>>2)] = value; break; + case 'double': HEAPF64[((ptr)>>3)] = value; break; default: abort('invalid type for setValue: ' + type); } } @@ -947,11 +950,11 @@ function stringToUTF16(str, outPtr, maxBytesToWrite) { for (var i = 0; i < numCharsToWrite; ++i) { // charCodeAt returns a UTF-16 encoded code unit, so it can be directly written to the HEAP. var codeUnit = str.charCodeAt(i); // possibly a lead surrogate - HEAP16[((outPtr)>>1)]=codeUnit; + HEAP16[((outPtr)>>1)] = codeUnit; outPtr += 2; } // Null-terminate the pointer to the HEAP. - HEAP16[((outPtr)>>1)]=0; + HEAP16[((outPtr)>>1)] = 0; return outPtr - startPtr; } @@ -1010,12 +1013,12 @@ function stringToUTF32(str, outPtr, maxBytesToWrite) { var trailSurrogate = str.charCodeAt(++i); codeUnit = 0x10000 + ((codeUnit & 0x3FF) << 10) | (trailSurrogate & 0x3FF); } - HEAP32[((outPtr)>>2)]=codeUnit; + HEAP32[((outPtr)>>2)] = codeUnit; outPtr += 4; if (outPtr + 4 > endPtr) break; } // Null-terminate the pointer to the HEAP. - HEAP32[((outPtr)>>2)]=0; + HEAP32[((outPtr)>>2)] = 0; return outPtr - startPtr; } @@ -1079,10 +1082,10 @@ function writeArrayToMemory(array, buffer) { /** @param {boolean=} dontAddNull */ function writeAsciiToMemory(str, buffer, dontAddNull) { for (var i = 0; i < str.length; ++i) { - HEAP8[((buffer++)>>0)]=str.charCodeAt(i); + HEAP8[((buffer++)>>0)] = str.charCodeAt(i); } // Null-terminate the pointer to the HEAP. - if (!dontAddNull) HEAP8[((buffer)>>0)]=0; + if (!dontAddNull) HEAP8[((buffer)>>0)] = 0; } @@ -1198,6 +1201,7 @@ var __ATPOSTRUN__ = []; // functions called after the main() is called var runtimeInitialized = false; var runtimeExited = false; +__ATINIT__.push({ func: function() { ___wasm_call_ctors() } }); function preRun() { @@ -1387,14 +1391,13 @@ if (!isDataURI(wasmBinaryFile)) { wasmBinaryFile = locateFile(wasmBinaryFile); } -function getBinary() { +function getBinary(file) { try { - if (wasmBinary) { + if (file == wasmBinaryFile && wasmBinary) { return new Uint8Array(wasmBinary); } - if (readBinary) { - return readBinary(wasmBinaryFile); + return readBinary(file); } else { throw "both async and sync fetching of the wasm failed"; } @@ -1405,23 +1408,36 @@ function getBinary() { } function getBinaryPromise() { - // If we don't have the binary yet, and have the Fetch api, use that; - // in some environments, like Electron's render process, Fetch api may be present, but have a different context than expected, let's only use it on the Web - if (!wasmBinary && (ENVIRONMENT_IS_WEB || ENVIRONMENT_IS_WORKER) && typeof fetch === 'function' - // Let's not use fetch to get objects over file:// as it's most likely Cordova which doesn't support fetch for file:// + // If we don't have the binary yet, try to to load it asynchronously. + // Fetch has some additional restrictions over XHR, like it can't be used on a file:// url. + // See https://github.com/github/fetch/pull/92#issuecomment-140665932 + // Cordova or Electron apps are typically loaded from a file:// url. + // So use fetch if it is available and the url is not a file, otherwise fall back to XHR. + if (!wasmBinary && (ENVIRONMENT_IS_WEB || ENVIRONMENT_IS_WORKER)) { + if (typeof fetch === 'function' && !isFileURI(wasmBinaryFile) - ) { - return fetch(wasmBinaryFile, { credentials: 'same-origin' }).then(function(response) { - if (!response['ok']) { - throw "failed to load wasm binary file at '" + wasmBinaryFile + "'"; + ) { + return fetch(wasmBinaryFile, { credentials: 'same-origin' }).then(function(response) { + if (!response['ok']) { + throw "failed to load wasm binary file at '" + wasmBinaryFile + "'"; + } + return response['arrayBuffer'](); + }).catch(function () { + return getBinary(wasmBinaryFile); + }); + } + else { + if (readAsync) { + // fetch is not available or url is file => try XHR (readAsync uses XHR internally) + return new Promise(function(resolve, reject) { + readAsync(wasmBinaryFile, function(response) { resolve(new Uint8Array(/** @type{!ArrayBuffer} */(response))) }, reject) + }); } - return response['arrayBuffer'](); - }).catch(function () { - return getBinary(); - }); + } } + // Otherwise, getBinary should be able to get it synchronously - return Promise.resolve().then(getBinary); + return Promise.resolve().then(function() { return getBinary(wasmBinaryFile); }); } @@ -1497,6 +1513,7 @@ function createWasm() { return instantiateArrayBuffer(receiveInstantiatedSource); } } + // User shell pages can write their own Module.instantiateWasm = function(imports, successCallback) callback // to manually instantiate the Wasm module themselves. This allows pages to run the instantiation parallel // to any other async startup actions they are performing. @@ -1514,7 +1531,7 @@ function createWasm() { return {}; // no exports yet; we'll fill them in later } -// Globals used by JS i64 conversions +// Globals used by JS i64 conversions (see makeSetValue) var tempDouble; var tempI64; @@ -1621,6 +1638,9 @@ var ASM_CONSTS = { var exceptionLast=0; function ___cxa_rethrow() { var catchInfo = exceptionCaught.pop(); + if (!catchInfo) { + abort('no exception to throw'); + } var info = catchInfo.get_exception_info(); var ptr = catchInfo.get_base_ptr(); if (!info.get_rethrown()) { @@ -1639,7 +1659,7 @@ var ASM_CONSTS = { this.ptr = excPtr - ExceptionInfoAttrs.SIZE; this.set_type = function(type) { - HEAP32[(((this.ptr)+(ExceptionInfoAttrs.TYPE_OFFSET))>>2)]=type; + HEAP32[(((this.ptr)+(ExceptionInfoAttrs.TYPE_OFFSET))>>2)] = type; }; this.get_type = function() { @@ -1647,7 +1667,7 @@ var ASM_CONSTS = { }; this.set_destructor = function(destructor) { - HEAP32[(((this.ptr)+(ExceptionInfoAttrs.DESTRUCTOR_OFFSET))>>2)]=destructor; + HEAP32[(((this.ptr)+(ExceptionInfoAttrs.DESTRUCTOR_OFFSET))>>2)] = destructor; }; this.get_destructor = function() { @@ -1655,12 +1675,12 @@ var ASM_CONSTS = { }; this.set_refcount = function(refcount) { - HEAP32[(((this.ptr)+(ExceptionInfoAttrs.REFCOUNT_OFFSET))>>2)]=refcount; + HEAP32[(((this.ptr)+(ExceptionInfoAttrs.REFCOUNT_OFFSET))>>2)] = refcount; }; this.set_caught = function (caught) { caught = caught ? 1 : 0; - HEAP8[(((this.ptr)+(ExceptionInfoAttrs.CAUGHT_OFFSET))>>0)]=caught; + HEAP8[(((this.ptr)+(ExceptionInfoAttrs.CAUGHT_OFFSET))>>0)] = caught; }; this.get_caught = function () { @@ -1669,7 +1689,7 @@ var ASM_CONSTS = { this.set_rethrown = function (rethrown) { rethrown = rethrown ? 1 : 0; - HEAP8[(((this.ptr)+(ExceptionInfoAttrs.RETHROWN_OFFSET))>>0)]=rethrown; + HEAP8[(((this.ptr)+(ExceptionInfoAttrs.RETHROWN_OFFSET))>>0)] = rethrown; }; this.get_rethrown = function () { @@ -1687,13 +1707,13 @@ var ASM_CONSTS = { this.add_ref = function() { var value = HEAP32[(((this.ptr)+(ExceptionInfoAttrs.REFCOUNT_OFFSET))>>2)]; - HEAP32[(((this.ptr)+(ExceptionInfoAttrs.REFCOUNT_OFFSET))>>2)]=value + 1; + HEAP32[(((this.ptr)+(ExceptionInfoAttrs.REFCOUNT_OFFSET))>>2)] = value + 1; }; // Returns true if last reference released. this.release_ref = function() { var prev = HEAP32[(((this.ptr)+(ExceptionInfoAttrs.REFCOUNT_OFFSET))>>2)]; - HEAP32[(((this.ptr)+(ExceptionInfoAttrs.REFCOUNT_OFFSET))>>2)]=prev - 1; + HEAP32[(((this.ptr)+(ExceptionInfoAttrs.REFCOUNT_OFFSET))>>2)] = prev - 1; return prev === 1; }; } @@ -1735,9 +1755,9 @@ var ASM_CONSTS = { // Coordinated Universal Time (UTC) and local standard time."), the same // as returned by stdTimezoneOffset. // See http://pubs.opengroup.org/onlinepubs/009695399/functions/tzset.html - HEAP32[((__get_timezone())>>2)]=stdTimezoneOffset * 60; + HEAP32[((__get_timezone())>>2)] = stdTimezoneOffset * 60; - HEAP32[((__get_daylight())>>2)]=Number(winterOffset != summerOffset); + HEAP32[((__get_daylight())>>2)] = Number(winterOffset != summerOffset); function extractZone(date) { var match = date.toTimeString().match(/\(([A-Za-z ]+)\)$/); @@ -1749,37 +1769,37 @@ var ASM_CONSTS = { var summerNamePtr = allocateUTF8(summerName); if (summerOffset < winterOffset) { // Northern hemisphere - HEAP32[((__get_tzname())>>2)]=winterNamePtr; - HEAP32[(((__get_tzname())+(4))>>2)]=summerNamePtr; + HEAP32[((__get_tzname())>>2)] = winterNamePtr; + HEAP32[(((__get_tzname())+(4))>>2)] = summerNamePtr; } else { - HEAP32[((__get_tzname())>>2)]=summerNamePtr; - HEAP32[(((__get_tzname())+(4))>>2)]=winterNamePtr; + HEAP32[((__get_tzname())>>2)] = summerNamePtr; + HEAP32[(((__get_tzname())+(4))>>2)] = winterNamePtr; } } function _localtime_r(time, tmPtr) { _tzset(); var date = new Date(HEAP32[((time)>>2)]*1000); - HEAP32[((tmPtr)>>2)]=date.getSeconds(); - HEAP32[(((tmPtr)+(4))>>2)]=date.getMinutes(); - HEAP32[(((tmPtr)+(8))>>2)]=date.getHours(); - HEAP32[(((tmPtr)+(12))>>2)]=date.getDate(); - HEAP32[(((tmPtr)+(16))>>2)]=date.getMonth(); - HEAP32[(((tmPtr)+(20))>>2)]=date.getFullYear()-1900; - HEAP32[(((tmPtr)+(24))>>2)]=date.getDay(); + HEAP32[((tmPtr)>>2)] = date.getSeconds(); + HEAP32[(((tmPtr)+(4))>>2)] = date.getMinutes(); + HEAP32[(((tmPtr)+(8))>>2)] = date.getHours(); + HEAP32[(((tmPtr)+(12))>>2)] = date.getDate(); + HEAP32[(((tmPtr)+(16))>>2)] = date.getMonth(); + HEAP32[(((tmPtr)+(20))>>2)] = date.getFullYear()-1900; + HEAP32[(((tmPtr)+(24))>>2)] = date.getDay(); var start = new Date(date.getFullYear(), 0, 1); var yday = ((date.getTime() - start.getTime()) / (1000 * 60 * 60 * 24))|0; - HEAP32[(((tmPtr)+(28))>>2)]=yday; - HEAP32[(((tmPtr)+(36))>>2)]=-(date.getTimezoneOffset() * 60); + HEAP32[(((tmPtr)+(28))>>2)] = yday; + HEAP32[(((tmPtr)+(36))>>2)] = -(date.getTimezoneOffset() * 60); // Attention: DST is in December in South, and some regions don't have DST at all. var summerOffset = new Date(date.getFullYear(), 6, 1).getTimezoneOffset(); var winterOffset = start.getTimezoneOffset(); var dst = (summerOffset != winterOffset && date.getTimezoneOffset() == Math.min(winterOffset, summerOffset))|0; - HEAP32[(((tmPtr)+(32))>>2)]=dst; + HEAP32[(((tmPtr)+(32))>>2)] = dst; var zonePtr = HEAP32[(((__get_tzname())+(dst ? 4 : 0))>>2)]; - HEAP32[(((tmPtr)+(40))>>2)]=zonePtr; + HEAP32[(((tmPtr)+(40))>>2)] = zonePtr; return tmPtr; } @@ -1805,7 +1825,7 @@ var ASM_CONSTS = { var _emscripten_get_now_is_monotonic=true;; function setErrNo(value) { - HEAP32[((___errno_location())>>2)]=value; + HEAP32[((___errno_location())>>2)] = value; return value; } function _clock_gettime(clk_id, tp) { @@ -1819,8 +1839,8 @@ var ASM_CONSTS = { setErrNo(28); return -1; } - HEAP32[((tp)>>2)]=(now/1000)|0; // seconds - HEAP32[(((tp)+(4))>>2)]=((now % 1000)*1000*1000)|0; // nanoseconds + HEAP32[((tp)>>2)] = (now/1000)|0; // seconds + HEAP32[(((tp)+(4))>>2)] = ((now % 1000)*1000*1000)|0; // nanoseconds return 0; } @@ -1836,7 +1856,6 @@ var ASM_CONSTS = { abort('OOM'); } function _emscripten_resize_heap(requestedSize) { - requestedSize = requestedSize >>> 0; abortOnCannotGrowMemory(requestedSize); } @@ -2263,15 +2282,9 @@ var ASM_CONSTS = { // add the new node to the parent if (parent) { parent.contents[name] = node; + parent.timestamp = node.timestamp; } return node; - },getFileDataAsRegularArray:function(node) { - if (node.contents && node.contents.subarray) { - var arr = []; - for (var i = 0; i < node.usedBytes; ++i) arr.push(node.contents[i]); - return arr; // Returns a copy of the original data. - } - return node.contents; // No-op, the file contents are already in a JS array. Return as-is. },getFileDataAsTypedArray:function(node) { if (!node.contents) return new Uint8Array(0); if (node.contents.subarray) return node.contents.subarray(0, node.usedBytes); // Make sure to not return excess unused bytes. @@ -2288,28 +2301,19 @@ var ASM_CONSTS = { var oldContents = node.contents; node.contents = new Uint8Array(newCapacity); // Allocate new storage. if (node.usedBytes > 0) node.contents.set(oldContents.subarray(0, node.usedBytes), 0); // Copy old data over to the new storage. - return; },resizeFileStorage:function(node, newSize) { if (node.usedBytes == newSize) return; if (newSize == 0) { node.contents = null; // Fully decommit when requesting a resize to zero. node.usedBytes = 0; - return; - } - if (!node.contents || node.contents.subarray) { // Resize a typed array if that is being used as the backing store. + } else { var oldContents = node.contents; node.contents = new Uint8Array(newSize); // Allocate new storage. if (oldContents) { node.contents.set(oldContents.subarray(0, Math.min(newSize, node.usedBytes))); // Copy old data over to the new storage. } node.usedBytes = newSize; - return; } - // Backing with a JS array. - if (!node.contents) node.contents = []; - if (node.contents.length > newSize) node.contents.length = newSize; - else while (node.contents.length < newSize) node.contents.push(0); - node.usedBytes = newSize; },node_ops:{getattr:function(node) { var attr = {}; // device numbers reuse inode numbers. @@ -2367,17 +2371,21 @@ var ASM_CONSTS = { } // do the internal rewiring delete old_node.parent.contents[old_node.name]; + old_node.parent.timestamp = Date.now() old_node.name = new_name; new_dir.contents[new_name] = old_node; + new_dir.timestamp = old_node.parent.timestamp; old_node.parent = new_dir; },unlink:function(parent, name) { delete parent.contents[name]; + parent.timestamp = Date.now(); },rmdir:function(parent, name) { var node = FS.lookupNode(parent, name); for (var i in node.contents) { throw new FS.ErrnoError(55); } delete parent.contents[name]; + parent.timestamp = Date.now(); },readdir:function(node) { var entries = ['.', '..']; for (var key in node.contents) { @@ -2456,9 +2464,10 @@ var ASM_CONSTS = { MEMFS.expandFileStorage(stream.node, offset + length); stream.node.usedBytes = Math.max(stream.node.usedBytes, offset + length); },mmap:function(stream, address, length, position, prot, flags) { - // We don't currently support location hints for the address of the mapping - assert(address === 0); - + if (address !== 0) { + // We don't currently support location hints for the address of the mapping + throw new FS.ErrnoError(28); + } if (!FS.isFile(stream.node.mode)) { throw new FS.ErrnoError(43); } @@ -3569,13 +3578,14 @@ var ASM_CONSTS = { FS.mkdir('/dev/shm'); FS.mkdir('/dev/shm/tmp'); },createSpecialDirectories:function() { - // create /proc/self/fd which allows /proc/self/fd/6 => readlink gives the name of the stream for fd 6 (see test_unistd_ttyname) + // create /proc/self/fd which allows /proc/self/fd/6 => readlink gives the + // name of the stream for fd 6 (see test_unistd_ttyname) FS.mkdir('/proc'); - FS.mkdir('/proc/self'); + var proc_self = FS.mkdir('/proc/self'); FS.mkdir('/proc/self/fd'); FS.mount({ mount: function() { - var node = FS.createNode('/proc/self', 'fd', 16384 | 511 /* 0777 */, 73); + var node = FS.createNode(proc_self, 'fd', 16384 | 511 /* 0777 */, 73); node.node_ops = { lookup: function(parent, name) { var fd = +name; @@ -4095,20 +4105,26 @@ var ASM_CONSTS = { }; openRequest.onerror = onerror; }}; - var SYSCALLS={mappings:{},DEFAULT_POLLMASK:5,umask:511,calculateAt:function(dirfd, path) { - if (path[0] !== '/') { - // relative path - var dir; - if (dirfd === -100) { - dir = FS.cwd(); - } else { - var dirstream = FS.getStream(dirfd); - if (!dirstream) throw new FS.ErrnoError(8); - dir = dirstream.path; - } - path = PATH.join2(dir, path); + var SYSCALLS={mappings:{},DEFAULT_POLLMASK:5,umask:511,calculateAt:function(dirfd, path, allowEmpty) { + if (path[0] === '/') { + return path; } - return path; + // relative path + var dir; + if (dirfd === -100) { + dir = FS.cwd(); + } else { + var dirstream = FS.getStream(dirfd); + if (!dirstream) throw new FS.ErrnoError(8); + dir = dirstream.path; + } + if (path.length == 0) { + if (!allowEmpty) { + throw new FS.ErrnoError(44);; + } + return dir; + } + return PATH.join2(dir, path); },doStat:function(func, path, buf) { try { var stat = func(path); @@ -4119,25 +4135,25 @@ var ASM_CONSTS = { } throw e; } - HEAP32[((buf)>>2)]=stat.dev; - HEAP32[(((buf)+(4))>>2)]=0; - HEAP32[(((buf)+(8))>>2)]=stat.ino; - HEAP32[(((buf)+(12))>>2)]=stat.mode; - HEAP32[(((buf)+(16))>>2)]=stat.nlink; - HEAP32[(((buf)+(20))>>2)]=stat.uid; - HEAP32[(((buf)+(24))>>2)]=stat.gid; - HEAP32[(((buf)+(28))>>2)]=stat.rdev; - HEAP32[(((buf)+(32))>>2)]=0; - (tempI64 = [stat.size>>>0,(tempDouble=stat.size,(+(Math.abs(tempDouble))) >= 1.0 ? (tempDouble > 0.0 ? ((Math.min((+(Math.floor((tempDouble)/4294967296.0))), 4294967295.0))|0)>>>0 : (~~((+(Math.ceil((tempDouble - +(((~~(tempDouble)))>>>0))/4294967296.0)))))>>>0) : 0)],HEAP32[(((buf)+(40))>>2)]=tempI64[0],HEAP32[(((buf)+(44))>>2)]=tempI64[1]); - HEAP32[(((buf)+(48))>>2)]=4096; - HEAP32[(((buf)+(52))>>2)]=stat.blocks; - HEAP32[(((buf)+(56))>>2)]=(stat.atime.getTime() / 1000)|0; - HEAP32[(((buf)+(60))>>2)]=0; - HEAP32[(((buf)+(64))>>2)]=(stat.mtime.getTime() / 1000)|0; - HEAP32[(((buf)+(68))>>2)]=0; - HEAP32[(((buf)+(72))>>2)]=(stat.ctime.getTime() / 1000)|0; - HEAP32[(((buf)+(76))>>2)]=0; - (tempI64 = [stat.ino>>>0,(tempDouble=stat.ino,(+(Math.abs(tempDouble))) >= 1.0 ? (tempDouble > 0.0 ? ((Math.min((+(Math.floor((tempDouble)/4294967296.0))), 4294967295.0))|0)>>>0 : (~~((+(Math.ceil((tempDouble - +(((~~(tempDouble)))>>>0))/4294967296.0)))))>>>0) : 0)],HEAP32[(((buf)+(80))>>2)]=tempI64[0],HEAP32[(((buf)+(84))>>2)]=tempI64[1]); + HEAP32[((buf)>>2)] = stat.dev; + HEAP32[(((buf)+(4))>>2)] = 0; + HEAP32[(((buf)+(8))>>2)] = stat.ino; + HEAP32[(((buf)+(12))>>2)] = stat.mode; + HEAP32[(((buf)+(16))>>2)] = stat.nlink; + HEAP32[(((buf)+(20))>>2)] = stat.uid; + HEAP32[(((buf)+(24))>>2)] = stat.gid; + HEAP32[(((buf)+(28))>>2)] = stat.rdev; + HEAP32[(((buf)+(32))>>2)] = 0; + (tempI64 = [stat.size>>>0,(tempDouble=stat.size,(+(Math.abs(tempDouble))) >= 1.0 ? (tempDouble > 0.0 ? ((Math.min((+(Math.floor((tempDouble)/4294967296.0))), 4294967295.0))|0)>>>0 : (~~((+(Math.ceil((tempDouble - +(((~~(tempDouble)))>>>0))/4294967296.0)))))>>>0) : 0)],HEAP32[(((buf)+(40))>>2)] = tempI64[0],HEAP32[(((buf)+(44))>>2)] = tempI64[1]); + HEAP32[(((buf)+(48))>>2)] = 4096; + HEAP32[(((buf)+(52))>>2)] = stat.blocks; + HEAP32[(((buf)+(56))>>2)] = (stat.atime.getTime() / 1000)|0; + HEAP32[(((buf)+(60))>>2)] = 0; + HEAP32[(((buf)+(64))>>2)] = (stat.mtime.getTime() / 1000)|0; + HEAP32[(((buf)+(68))>>2)] = 0; + HEAP32[(((buf)+(72))>>2)] = (stat.ctime.getTime() / 1000)|0; + HEAP32[(((buf)+(76))>>2)] = 0; + (tempI64 = [stat.ino>>>0,(tempDouble=stat.ino,(+(Math.abs(tempDouble))) >= 1.0 ? (tempDouble > 0.0 ? ((Math.min((+(Math.floor((tempDouble)/4294967296.0))), 4294967295.0))|0)>>>0 : (~~((+(Math.ceil((tempDouble - +(((~~(tempDouble)))>>>0))/4294967296.0)))))>>>0) : 0)],HEAP32[(((buf)+(80))>>2)] = tempI64[0],HEAP32[(((buf)+(84))>>2)] = tempI64[1]); return 0; },doMsync:function(addr, stream, len, flags, offset) { var buffer = HEAPU8.slice(addr, addr + len); @@ -4232,6 +4248,38 @@ var ASM_CONSTS = { },get64:function(low, high) { return low; }}; + function _environ_get(__environ, environ_buf) {try { + + var bufSize = 0; + getEnvStrings().forEach(function(string, i) { + var ptr = environ_buf + bufSize; + HEAP32[(((__environ)+(i * 4))>>2)] = ptr; + writeAsciiToMemory(string, ptr); + bufSize += string.length + 1; + }); + return 0; + } catch (e) { + if (typeof FS === 'undefined' || !(e instanceof FS.ErrnoError)) abort(e); + return e.errno; + } + } + + function _environ_sizes_get(penviron_count, penviron_buf_size) {try { + + var strings = getEnvStrings(); + HEAP32[((penviron_count)>>2)] = strings.length; + var bufSize = 0; + strings.forEach(function(string) { + bufSize += string.length + 1; + }); + HEAP32[((penviron_buf_size)>>2)] = bufSize; + return 0; + } catch (e) { + if (typeof FS === 'undefined' || !(e instanceof FS.ErrnoError)) abort(e); + return e.errno; + } + } + function _fd_close(fd) {try { var stream = SYSCALLS.getStreamFromFD(fd); @@ -4247,7 +4295,7 @@ var ASM_CONSTS = { var stream = SYSCALLS.getStreamFromFD(fd); var num = SYSCALLS.doReadv(stream, iov, iovcnt); - HEAP32[((pnum)>>2)]=num + HEAP32[((pnum)>>2)] = num return 0; } catch (e) { if (typeof FS === 'undefined' || !(e instanceof FS.ErrnoError)) abort(e); @@ -4270,7 +4318,7 @@ var ASM_CONSTS = { } FS.llseek(stream, offset, whence); - (tempI64 = [stream.position>>>0,(tempDouble=stream.position,(+(Math.abs(tempDouble))) >= 1.0 ? (tempDouble > 0.0 ? ((Math.min((+(Math.floor((tempDouble)/4294967296.0))), 4294967295.0))|0)>>>0 : (~~((+(Math.ceil((tempDouble - +(((~~(tempDouble)))>>>0))/4294967296.0)))))>>>0) : 0)],HEAP32[((newOffset)>>2)]=tempI64[0],HEAP32[(((newOffset)+(4))>>2)]=tempI64[1]); + (tempI64 = [stream.position>>>0,(tempDouble=stream.position,(+(Math.abs(tempDouble))) >= 1.0 ? (tempDouble > 0.0 ? ((Math.min((+(Math.floor((tempDouble)/4294967296.0))), 4294967295.0))|0)>>>0 : (~~((+(Math.ceil((tempDouble - +(((~~(tempDouble)))>>>0))/4294967296.0)))))>>>0) : 0)],HEAP32[((newOffset)>>2)] = tempI64[0],HEAP32[(((newOffset)+(4))>>2)] = tempI64[1]); if (stream.getdents && offset === 0 && whence === 0) stream.getdents = null; // reset readdir state return 0; } catch (e) { @@ -4283,7 +4331,7 @@ var ASM_CONSTS = { var stream = SYSCALLS.getStreamFromFD(fd); var num = SYSCALLS.doWritev(stream, iov, iovcnt); - HEAP32[((pnum)>>2)]=num + HEAP32[((pnum)>>2)] = num return 0; } catch (e) { if (typeof FS === 'undefined' || !(e instanceof FS.ErrnoError)) abort(e); @@ -4732,8 +4780,6 @@ function intArrayToString(array) { } - -__ATINIT__.push({ func: function() { ___wasm_call_ctors() } }); var asmLibraryArg = { "__cxa_allocate_exception": ___cxa_allocate_exception, "__cxa_atexit": ___cxa_atexit, @@ -4966,7 +5012,10 @@ function run(args) { preRun(); - if (runDependencies > 0) return; // a preRun added a dependency, run will be called later + // a preRun added a dependency, run will be called later + if (runDependencies > 0) { + return; + } function doRun() { // run may have just been called through dependencies being fulfilled just in this very frame, @@ -5037,9 +5086,6 @@ if (Module['preInit']) { } } - - noExitRuntime = true; - run(); diff --git a/GUI/fibre-js/libfibre-wasm.wasm b/GUI/fibre-js/libfibre-wasm.wasm index e782915a..9e275771 100755 Binary files a/GUI/fibre-js/libfibre-wasm.wasm and b/GUI/fibre-js/libfibre-wasm.wasm differ