Backed out changeset 7c90ac565923 (
bug 927560)
--- a/toolkit/components/osfile/modules/osfile_async_front.jsm
+++ b/toolkit/components/osfile/modules/osfile_async_front.jsm
@@ -133,46 +133,43 @@ let clone = function clone(object, refs
result[k] = object[k];
} else {
refer(result, k, object);
}
}
return result;
};
-let worker = null;
+let worker = new PromiseWorker(
+ "resource://gre/modules/osfile/osfile_async_worker.js", LOG);
let Scheduler = {
/**
* |true| once we have sent at least one message to the worker.
- * This field is unaffected by resetting the worker.
*/
- launched: false,
+ launched: false,
/**
* |true| once shutdown has begun i.e. we should reject any
- * message, including resets.
+ * message
*/
shutdown: false,
/**
* The latest promise returned.
*/
latestPromise: Promise.resolve("OS.File scheduler hasn't been launched yet"),
post: function post(...args) {
this.launched = true;
+
if (this.shutdown) {
LOG("OS.File is not available anymore. The following request has been rejected.", args);
return Promise.reject(new Error("OS.File has been shut down."));
}
- if (!worker) {
- // Either the worker has never been created or it has been reset
- worker = new PromiseWorker(
- "resource://gre/modules/osfile/osfile_async_worker.js", LOG);
- }
+
// By convention, the last argument of any message may be an |options| object.
let methodArgs = args[1];
let options = methodArgs ? methodArgs[methodArgs.length - 1] : null;
let promise = worker.post.apply(worker, args);
return this.latestPromise = promise.then(
function onSuccess(data) {
// Check for duration and return result.
if (!options) {
@@ -992,61 +989,24 @@ if (OS.Constants.Win) {
} else {
throw new Error("I am neither under Windows nor under a Posix system");
}
DirectoryIterator.Entry.fromMsg = function fromMsg(value) {
return new DirectoryIterator.Entry(value);
};
-/**
- * Flush all operations currently queued, then kill the underlying
- * worker to save memory.
- *
- * @return {Promise}
- * @reject {Error} If at least one file or directory iterator instance
- * is still open and the worker cannot be killed safely.
- */
-File.resetWorker = function() {
- if (!Scheduler.launched || Scheduler.shutdown) {
- // No need to reset
- return Promise.resolve();
- }
- return Scheduler.post("Meta_reset").then(
- function(wouldLeak) {
- if (!wouldLeak) {
- // No resource would leak, the worker was stopped.
- worker = null;
- return;
- }
- // Otherwise, resetting would be unsafe and has been canceled.
- // Turn this into an error
- let msg = "Cannot reset worker: ";
- let {openedFiles, openedDirectoryIterators} = wouldLeak;
- if (openedFiles.length > 0) {
- msg += "The following files are still open:\n" +
- openedFiles.join("\n");
- }
- if (openedDirectoryIterators.length > 0) {
- msg += "The following directory iterators are still open:\n" +
- openedDirectoryIterators.join("\n");
- }
- throw new Error(msg);
- }
- );
-};
-
// Constants
Object.defineProperty(File, "POS_START", {value: OS.Shared.POS_START});
Object.defineProperty(File, "POS_CURRENT", {value: OS.Shared.POS_CURRENT});
Object.defineProperty(File, "POS_END", {value: OS.Shared.POS_END});
-this.OS.File = File;
-this.OS.File.Error = OSError;
-this.OS.File.DirectoryIterator = DirectoryIterator;
+OS.File = File;
+OS.File.Error = OSError;
+OS.File.DirectoryIterator = DirectoryIterator;
// Auto-flush OS.File during profile-before-change. This ensures that any I/O
// that has been queued *before* profile-before-change is properly completed.
// To ensure that I/O queued *during* profile-before-change is completed,
// clients should register using AsyncShutdown.addBlocker.
AsyncShutdown.profileBeforeChange.addBlocker(
"OS.File: flush I/O queued before profile-before-change",
--- a/toolkit/components/osfile/modules/osfile_async_worker.js
+++ b/toolkit/components/osfile/modules/osfile_async_worker.js
@@ -62,28 +62,20 @@ if (this.Components) {
}
// Now, post a reply, possibly as an uncaught error.
// We post this message from outside the |try ... catch| block
// to avoid capturing errors that take place during |postMessage| and
// built-in serialization.
if (!exn) {
LOG("Sending positive reply", result, "id is", id);
- if (result instanceof Meta) {
- if ("transfers" in result.meta) {
- // Take advantage of zero-copy transfers
- self.postMessage({ok: result.data, id: id, durationMs: durationMs},
- result.meta.transfers);
- } else {
- self.postMessage({ok: result.data, id:id, durationMs: durationMs});
- }
- if (result.meta.shutdown || false) {
- // Time to close the worker
- self.close();
- }
+ if (result instanceof Transfer) {
+ // Take advantage of zero-copy transfers
+ self.postMessage({ok: result.data, id: id, durationMs: durationMs},
+ result.transfers);
} else {
self.postMessage({ok: result, id:id, durationMs: durationMs});
}
} else if (exn == StopIteration) {
// StopIteration cannot be serialized automatically
LOG("Sending back StopIteration");
self.postMessage({StopIteration: true, id: id, durationMs: durationMs});
} else if (exn instanceof exports.OS.File.Error) {
@@ -195,35 +187,30 @@ if (this.Components) {
}
return f.call(file);
};
let Type = exports.OS.Shared.Type;
let File = exports.OS.File;
- /**
- * A constructor used to return data to the caller thread while
- * also executing some specific treatment (e.g. shutting down
- * the current thread, transmitting data instead of copying it).
- *
- * @param {object=} data The data to return to the caller thread.
- * @param {object=} meta Additional instructions, as an object
- * that may contain the following fields:
- * - {bool} shutdown If |true|, shut down the current thread after
- * having sent the result.
- * - {Array} transfers An array of objects that should be transferred
- * instead of being copied.
- *
- * @constructor
- */
- let Meta = function Meta(data, meta) {
- this.data = data;
- this.meta = meta;
- };
+ /**
+ * A constructor used to transfer data to the caller
+ * without copy.
+ *
+ * @param {*} data The data to return to the caller.
+ * @param {Array} transfers An array of Transferable
+ * values that should be moved instead of being copied.
+ *
+ * @constructor
+ */
+ let Transfer = function Transfer(data, transfers) {
+ this.data = data;
+ this.transfers = transfers;
+ };
/**
* 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.
*/
@@ -242,38 +229,16 @@ if (this.Components) {
// Return information about both opened files and opened
// directory iterators.
return {
openedFiles: OpenedFiles.listOpenedResources(),
openedDirectoryIterators:
OpenedDirectoryIterators.listOpenedResources()
};
},
- Meta_reset: function() {
- // Attempt to stop the worker. This fails if at least one
- // resource is still open. Returns the list of files and
- // directory iterators that cannot be closed safely (or undefined
- // if there are no such files/directory iterators).
- let openedFiles = OpenedFiles.listOpenedResources();
- let openedDirectoryIterators =
- OpenedDirectoryIterators.listOpenedResources();
- let canShutdown = openedFiles.length == 0
- && openedDirectoryIterators.length == 0;
- if (canShutdown) {
- // Succeed. Shutdown the thread, nothing to return
- return new Meta(null, {shutdown: true});
- } else {
- // Fail. Don't shutdown the thread, return info on resources
- return {
- openedFiles: openedFiles,
- openedDirectoryIterators: openedDirectoryIterators
- };
- }
- },
-
// Functions of OS.File
stat: function stat(path) {
return exports.OS.File.Info.toMsg(
exports.OS.File.stat(Type.path.fromMsg(path)));
},
getCurrentDirectory: function getCurrentDirectory() {
return exports.OS.Shared.Type.path.toMsg(File.getCurrentDirectory());
},
@@ -303,23 +268,17 @@ if (this.Components) {
return OpenedFiles.add(file, {
// Adding path information to keep track of opened files
// to report leaks when debugging.
path: filePath
});
},
read: function read(path, bytes, options) {
let data = File.read(Type.path.fromMsg(path), bytes);
- return new Meta({
- buffer: data.buffer,
- byteOffset: data.byteOffset,
- byteLength: data.byteLength
- }, {
- transfers: [data.buffer]
- });
+ return new Transfer({buffer: data.buffer, byteOffset: data.byteOffset, byteLength: data.byteLength}, [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);
}
@@ -353,23 +312,17 @@ if (this.Components) {
function do_stat() {
return exports.OS.File.Info.toMsg(this.stat());
});
},
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]
- });
+ return new Transfer({buffer: data.buffer, byteOffset: data.byteOffset, byteLength: data.byteLength}, [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);