summaryrefslogtreecommitdiffstats
path: root/toolkit/components/osfile/modules/osfile_async_worker.js
diff options
context:
space:
mode:
authorMatt A. Tobin <mattatobin@localhost.localdomain>2018-02-02 04:16:08 -0500
committerMatt A. Tobin <mattatobin@localhost.localdomain>2018-02-02 04:16:08 -0500
commit5f8de423f190bbb79a62f804151bc24824fa32d8 (patch)
tree10027f336435511475e392454359edea8e25895d /toolkit/components/osfile/modules/osfile_async_worker.js
parent49ee0794b5d912db1f95dce6eb52d781dc210db5 (diff)
downloadUXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar
UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.gz
UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.lz
UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.xz
UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.zip
Add m-esr52 at 52.6.0
Diffstat (limited to 'toolkit/components/osfile/modules/osfile_async_worker.js')
-rw-r--r--toolkit/components/osfile/modules/osfile_async_worker.js407
1 files changed, 407 insertions, 0 deletions
diff --git a/toolkit/components/osfile/modules/osfile_async_worker.js b/toolkit/components/osfile/modules/osfile_async_worker.js
new file mode 100644
index 000000000..84287c75e
--- /dev/null
+++ b/toolkit/components/osfile/modules/osfile_async_worker.js
@@ -0,0 +1,407 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+
+if (this.Components) {
+ throw new Error("This worker can only be loaded from a worker thread");
+}
+
+// Worker thread for osfile asynchronous front-end
+
+(function(exports) {
+ "use strict";
+
+ // Timestamps, for use in Telemetry.
+ // The object is set to |null| once it has been sent
+ // to the main thread.
+ let timeStamps = {
+ entered: Date.now(),
+ loaded: null
+ };
+
+ importScripts("resource://gre/modules/osfile.jsm");
+
+ let PromiseWorker = require("resource://gre/modules/workers/PromiseWorker.js");
+ let SharedAll = require("resource://gre/modules/osfile/osfile_shared_allthreads.jsm");
+ let LOG = SharedAll.LOG.bind(SharedAll, "Agent");
+
+ let worker = new PromiseWorker.AbstractWorker();
+ worker.dispatch = function(method, args = []) {
+ return Agent[method](...args);
+ },
+ worker.log = LOG;
+ worker.postMessage = function(message, ...transfers) {
+ if (timeStamps) {
+ message.timeStamps = timeStamps;
+ timeStamps = null;
+ }
+ self.postMessage(message, ...transfers);
+ };
+ worker.close = function() {
+ self.close();
+ };
+ let Meta = PromiseWorker.Meta;
+
+ self.addEventListener("message", msg => worker.handleMessage(msg));
+
+ /**
+ * A data structure used to track opened resources
+ */
+ let ResourceTracker = function ResourceTracker() {
+ // A number used to generate ids
+ this._idgen = 0;
+ // A map from id to resource
+ this._map = new Map();
+ };
+ ResourceTracker.prototype = {
+ /**
+ * Get a resource from its unique identifier.
+ */
+ get: function(id) {
+ let result = this._map.get(id);
+ if (result == null) {
+ return result;
+ }
+ return result.resource;
+ },
+ /**
+ * Remove a resource from its unique identifier.
+ */
+ remove: function(id) {
+ if (!this._map.has(id)) {
+ throw new Error("Cannot find resource id " + id);
+ }
+ this._map.delete(id);
+ },
+ /**
+ * Add a resource, return a new unique identifier
+ *
+ * @param {*} resource A resource.
+ * @param {*=} info Optional information. For debugging purposes.
+ *
+ * @return {*} A unique identifier. For the moment, this is a number,
+ * but this might not remain the case forever.
+ */
+ add: function(resource, info) {
+ let id = this._idgen++;
+ this._map.set(id, {resource:resource, info:info});
+ return id;
+ },
+ /**
+ * Return a list of all open resources i.e. the ones still present in
+ * ResourceTracker's _map.
+ */
+ listOpenedResources: function listOpenedResources() {
+ return Array.from(this._map, ([id, resource]) => resource.info.path);
+ }
+ };
+
+ /**
+ * A map of unique identifiers to opened files.
+ */
+ let OpenedFiles = new ResourceTracker();
+
+ /**
+ * Execute a function in the context of a given file.
+ *
+ * @param {*} id A unique identifier, as used by |OpenFiles|.
+ * @param {Function} f A function to call.
+ * @param {boolean} ignoreAbsent If |true|, the error is ignored. Otherwise, the error causes an exception.
+ * @return The return value of |f()|
+ *
+ * This function attempts to get the file matching |id|. If
+ * the file exists, it executes |f| within the |this| set
+ * to the corresponding file. Otherwise, it throws an error.
+ */
+ let withFile = function withFile(id, f, ignoreAbsent) {
+ let file = OpenedFiles.get(id);
+ if (file == null) {
+ if (!ignoreAbsent) {
+ throw OS.File.Error.closed("accessing file");
+ }
+ return undefined;
+ }
+ return f.call(file);
+ };
+
+ let OpenedDirectoryIterators = new ResourceTracker();
+ let withDir = function withDir(fd, f, ignoreAbsent) {
+ let file = OpenedDirectoryIterators.get(fd);
+ if (file == null) {
+ if (!ignoreAbsent) {
+ throw OS.File.Error.closed("accessing directory");
+ }
+ return undefined;
+ }
+ if (!(file instanceof File.DirectoryIterator)) {
+ throw new Error("file is not a directory iterator " + file.__proto__.toSource());
+ }
+ return f.call(file);
+ };
+
+ let Type = exports.OS.Shared.Type;
+
+ let File = exports.OS.File;
+
+ /**
+ * The agent.
+ *
+ * It is in charge of performing method-specific deserialization
+ * of messages, calling the function/method of OS.File and serializing
+ * back the results.
+ */
+ let Agent = {
+ // Update worker's OS.Shared.DEBUG flag message from controller.
+ SET_DEBUG: function(aDEBUG) {
+ SharedAll.Config.DEBUG = aDEBUG;
+ },
+ // Return worker's current OS.Shared.DEBUG value to controller.
+ // Note: This is used for testing purposes.
+ GET_DEBUG: function() {
+ return SharedAll.Config.DEBUG;
+ },
+ /**
+ * Execute shutdown sequence, returning data on leaked file descriptors.
+ *
+ * @param {bool} If |true|, kill the worker if this would not cause
+ * leaks.
+ */
+ Meta_shutdown: function(kill) {
+ let result = {
+ openedFiles: OpenedFiles.listOpenedResources(),
+ openedDirectoryIterators: OpenedDirectoryIterators.listOpenedResources(),
+ killed: false // Placeholder
+ };
+
+ // Is it safe to kill the worker?
+ let safe = result.openedFiles.length == 0
+ && result.openedDirectoryIterators.length == 0;
+ result.killed = safe && kill;
+
+ return new Meta(result, {shutdown: result.killed});
+ },
+ // Functions of OS.File
+ stat: function stat(path, options) {
+ return exports.OS.File.Info.toMsg(
+ exports.OS.File.stat(Type.path.fromMsg(path), options));
+ },
+ setPermissions: function setPermissions(path, options = {}) {
+ return exports.OS.File.setPermissions(Type.path.fromMsg(path), options);
+ },
+ setDates: function setDates(path, accessDate, modificationDate) {
+ return exports.OS.File.setDates(Type.path.fromMsg(path), accessDate,
+ modificationDate);
+ },
+ getCurrentDirectory: function getCurrentDirectory() {
+ return exports.OS.Shared.Type.path.toMsg(File.getCurrentDirectory());
+ },
+ setCurrentDirectory: function setCurrentDirectory(path) {
+ File.setCurrentDirectory(exports.OS.Shared.Type.path.fromMsg(path));
+ },
+ copy: function copy(sourcePath, destPath, options) {
+ return File.copy(Type.path.fromMsg(sourcePath),
+ Type.path.fromMsg(destPath), options);
+ },
+ move: function move(sourcePath, destPath, options) {
+ return File.move(Type.path.fromMsg(sourcePath),
+ Type.path.fromMsg(destPath), options);
+ },
+ getAvailableFreeSpace: function getAvailableFreeSpace(sourcePath) {
+ return Type.uint64_t.toMsg(
+ File.getAvailableFreeSpace(Type.path.fromMsg(sourcePath)));
+ },
+ makeDir: function makeDir(path, options) {
+ return File.makeDir(Type.path.fromMsg(path), options);
+ },
+ removeEmptyDir: function removeEmptyDir(path, options) {
+ return File.removeEmptyDir(Type.path.fromMsg(path), options);
+ },
+ remove: function remove(path, options) {
+ return File.remove(Type.path.fromMsg(path), options);
+ },
+ open: function open(path, mode, options) {
+ let filePath = Type.path.fromMsg(path);
+ let file = File.open(filePath, mode, options);
+ return OpenedFiles.add(file, {
+ // Adding path information to keep track of opened files
+ // to report leaks when debugging.
+ path: filePath
+ });
+ },
+ openUnique: function openUnique(path, options) {
+ let filePath = Type.path.fromMsg(path);
+ let openedFile = OS.Shared.AbstractFile.openUnique(filePath, options);
+ let resourceId = OpenedFiles.add(openedFile.file, {
+ // Adding path information to keep track of opened files
+ // to report leaks when debugging.
+ path: openedFile.path
+ });
+
+ return {
+ path: openedFile.path,
+ file: resourceId
+ };
+ },
+ read: function read(path, bytes, options) {
+ let data = File.read(Type.path.fromMsg(path), bytes, options);
+ if (typeof data == "string") {
+ return data;
+ }
+ return new Meta({
+ buffer: data.buffer,
+ byteOffset: data.byteOffset,
+ byteLength: data.byteLength
+ }, {
+ transfers: [data.buffer]
+ });
+ },
+ exists: function exists(path) {
+ return File.exists(Type.path.fromMsg(path));
+ },
+ writeAtomic: function writeAtomic(path, buffer, options) {
+ if (options.tmpPath) {
+ options.tmpPath = Type.path.fromMsg(options.tmpPath);
+ }
+ return File.writeAtomic(Type.path.fromMsg(path),
+ Type.voidptr_t.fromMsg(buffer),
+ options
+ );
+ },
+ removeDir: function(path, options) {
+ return File.removeDir(Type.path.fromMsg(path), options);
+ },
+ new_DirectoryIterator: function new_DirectoryIterator(path, options) {
+ let directoryPath = Type.path.fromMsg(path);
+ let iterator = new File.DirectoryIterator(directoryPath, options);
+ return OpenedDirectoryIterators.add(iterator, {
+ // Adding path information to keep track of opened directory
+ // iterators to report leaks when debugging.
+ path: directoryPath
+ });
+ },
+ // Methods of OS.File
+ File_prototype_close: function close(fd) {
+ return withFile(fd,
+ function do_close() {
+ try {
+ return this.close();
+ } finally {
+ OpenedFiles.remove(fd);
+ }
+ });
+ },
+ File_prototype_stat: function stat(fd) {
+ return withFile(fd,
+ function do_stat() {
+ return exports.OS.File.Info.toMsg(this.stat());
+ });
+ },
+ File_prototype_setPermissions: function setPermissions(fd, options = {}) {
+ return withFile(fd,
+ function do_setPermissions() {
+ return this.setPermissions(options);
+ });
+ },
+ File_prototype_setDates: function setDates(fd, accessTime, modificationTime) {
+ return withFile(fd,
+ function do_setDates() {
+ return this.setDates(accessTime, modificationTime);
+ });
+ },
+ File_prototype_read: function read(fd, nbytes, options) {
+ return withFile(fd,
+ function do_read() {
+ let data = this.read(nbytes, options);
+ return new Meta({
+ buffer: data.buffer,
+ byteOffset: data.byteOffset,
+ byteLength: data.byteLength
+ }, {
+ transfers: [data.buffer]
+ });
+ }
+ );
+ },
+ File_prototype_readTo: function readTo(fd, buffer, options) {
+ return withFile(fd,
+ function do_readTo() {
+ return this.readTo(exports.OS.Shared.Type.voidptr_t.fromMsg(buffer),
+ options);
+ });
+ },
+ File_prototype_write: function write(fd, buffer, options) {
+ return withFile(fd,
+ function do_write() {
+ return this.write(exports.OS.Shared.Type.voidptr_t.fromMsg(buffer),
+ options);
+ });
+ },
+ File_prototype_setPosition: function setPosition(fd, pos, whence) {
+ return withFile(fd,
+ function do_setPosition() {
+ return this.setPosition(pos, whence);
+ });
+ },
+ File_prototype_getPosition: function getPosition(fd) {
+ return withFile(fd,
+ function do_getPosition() {
+ return this.getPosition();
+ });
+ },
+ File_prototype_flush: function flush(fd) {
+ return withFile(fd,
+ function do_flush() {
+ return this.flush();
+ });
+ },
+ // Methods of OS.File.DirectoryIterator
+ DirectoryIterator_prototype_next: function next(dir) {
+ return withDir(dir,
+ function do_next() {
+ try {
+ return File.DirectoryIterator.Entry.toMsg(this.next());
+ } catch (x) {
+ if (x == StopIteration) {
+ OpenedDirectoryIterators.remove(dir);
+ }
+ throw x;
+ }
+ }, false);
+ },
+ DirectoryIterator_prototype_nextBatch: function nextBatch(dir, size) {
+ return withDir(dir,
+ function do_nextBatch() {
+ let result;
+ try {
+ result = this.nextBatch(size);
+ } catch (x) {
+ OpenedDirectoryIterators.remove(dir);
+ throw x;
+ }
+ return result.map(File.DirectoryIterator.Entry.toMsg);
+ }, false);
+ },
+ DirectoryIterator_prototype_close: function close(dir) {
+ return withDir(dir,
+ function do_close() {
+ this.close();
+ OpenedDirectoryIterators.remove(dir);
+ }, true);// ignore error to support double-closing |DirectoryIterator|
+ },
+ DirectoryIterator_prototype_exists: function exists(dir) {
+ return withDir(dir,
+ function do_exists() {
+ return this.exists();
+ });
+ }
+ };
+ if (!SharedAll.Constants.Win) {
+ Agent.unixSymLink = function unixSymLink(sourcePath, destPath) {
+ return File.unixSymLink(Type.path.fromMsg(sourcePath),
+ Type.path.fromMsg(destPath));
+ };
+ }
+
+ timeStamps.loaded = Date.now();
+})(this);