Bug 1454618 - FileReaderSync must work also after a self.close(), r=asuth
authorAndrea Marchesini <amarchesini@mozilla.com>
Wed, 18 Apr 2018 10:02:29 +0200
changeset 414228 6b80d13e112b4997fd4cf5407bbcafbbb543544c
parent 414227 f5f4089f457e85f1f485bd0411bd4cf1d30d487e
child 414229 3c4261ce506185df17964ad81f8e8a7f4ee6c885
push id33861
push userccoroiu@mozilla.com
push dateWed, 18 Apr 2018 10:50:38 +0000
treeherdermozilla-central@4af4ae0aee55 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersasuth
bugs1454618
milestone61.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1454618 - FileReaderSync must work also after a self.close(), r=asuth
dom/file/FileReaderSync.cpp
dom/workers/WorkerPrivate.cpp
dom/workers/test/mochitest.ini
dom/workers/test/script_createFile.js
dom/workers/test/test_fileReaderSync_when_closing.html
--- a/dom/file/FileReaderSync.cpp
+++ b/dom/file/FileReaderSync.cpp
@@ -438,17 +438,17 @@ FileReaderSync::SyncRead(nsIInputStream*
   nsCOMPtr<nsIAsyncInputStream> asyncStream = do_QueryInterface(aStream);
   if (!asyncStream) {
     return rv;
   }
 
   WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate();
   MOZ_ASSERT(workerPrivate);
 
-  AutoSyncLoopHolder syncLoop(workerPrivate, Closing);
+  AutoSyncLoopHolder syncLoop(workerPrivate, Terminating);
 
   nsCOMPtr<nsIEventTarget> syncLoopTarget = syncLoop.GetEventTarget();
   if (!syncLoopTarget) {
     // SyncLoop creation can fail if the worker is shutting down.
     return NS_ERROR_DOM_INVALID_STATE_ERR;
   }
 
   RefPtr<ReadCallback> callback =
--- a/dom/workers/WorkerPrivate.cpp
+++ b/dom/workers/WorkerPrivate.cpp
@@ -4120,16 +4120,18 @@ WorkerPrivate::CancelAllTimeouts()
   mTimer = nullptr;
   mTimerRunnable = nullptr;
 }
 
 already_AddRefed<nsIEventTarget>
 WorkerPrivate::CreateNewSyncLoop(WorkerStatus aFailStatus)
 {
   AssertIsOnWorkerThread();
+  MOZ_ASSERT(aFailStatus >= Terminating,
+             "Sync loops can be created when the worker is in Running/Closing state!");
 
   {
     MutexAutoLock lock(mMutex);
 
     if (mStatus >= aFailStatus) {
       return nullptr;
     }
   }
--- a/dom/workers/test/mochitest.ini
+++ b/dom/workers/test/mochitest.ini
@@ -192,8 +192,9 @@ scheme=https
 [test_navigator_workers_hardwareConcurrency.html]
 [test_bug1278777.html]
 [test_setTimeoutWith0.html]
 [test_bug1301094.html]
 [test_subworkers_suspended.html]
 skip-if = toolkit == 'android' #bug 1366501
 [test_bug1317725.html]
 [test_sharedworker_event_listener_leaks.html]
+[test_fileReaderSync_when_closing.html]
--- a/dom/workers/test/script_createFile.js
+++ b/dom/workers/test/script_createFile.js
@@ -1,14 +1,35 @@
-Cu.importGlobalProperties(["File", "Directory"]);
+Cu.importGlobalProperties(["File"]);
 
 addMessageListener("file.open", function (e) {
   var tmpFile = Cc["@mozilla.org/file/directory_service;1"]
                   .getService(Ci.nsIDirectoryService)
                   .QueryInterface(Ci.nsIProperties)
                   .get('TmpD', Ci.nsIFile)
   tmpFile.append('file.txt');
   tmpFile.createUnique(Ci.nsIFile.FILE_TYPE, 0o600);
 
   File.createFromNsIFile(tmpFile).then(function(file) {
     sendAsyncMessage("file.opened", { data: file });
   });
 });
+
+addMessageListener("nonEmptyFile.open", function (e) {
+  var tmpFile = Cc["@mozilla.org/file/directory_service;1"]
+                  .getService(Ci.nsIDirectoryService)
+                  .QueryInterface(Ci.nsIProperties)
+                  .get('TmpD', Ci.nsIFile)
+  tmpFile.append('file.txt');
+  tmpFile.createUnique(Ci.nsIFile.FILE_TYPE, 0o600);
+
+  var outStream = Cc["@mozilla.org/network/file-output-stream;1"].createInstance(Ci.nsIFileOutputStream); 
+  outStream.init(tmpFile, 0x02 | 0x08 | 0x20, // write, create, truncate
+                 0o666, 0);                         
+  var fileData = "Hello world!";
+  outStream.write(fileData, fileData.length);
+  outStream.close();                           
+
+
+  File.createFromNsIFile(tmpFile).then(function(file) {
+    sendAsyncMessage("nonEmptyFile.opened", { data: file });
+  });
+});
new file mode 100644
--- /dev/null
+++ b/dom/workers/test/test_fileReaderSync_when_closing.html
@@ -0,0 +1,54 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+  <meta charset="utf-8">
+  <title>Test for FileReaderSync when the worker is closing</title>
+  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+  <script type="application/javascript">
+
+// In order to exercise FileReaderSync::SyncRead's syncLoop-using AsyncWait()
+// path, we need to provide a stream that will both 1) not have all the data
+// immediately available (eliminating memory-backed Blobs) and 2) return
+// NS_BASE_STREAM_WOULD_BLOCK.  Under e10s, any Blob/File sourced from the
+// parent process (as loadChromeScript performs) will be backed by an
+// IPCBlobInputStream and will behave this way on first use (when it is in the
+// eInit state).  For ease of testing, we reuse script_createFile.js which
+// involves a file on disk, but a memory-backed Blob from the parent process
+// would be equally fine.  Under non-e10s, this File will not do the right
+// thing because a synchronous nsFileInputStream will be made directly
+// available and the AsyncWait path won't be taken, but the test will still
+// pass.
+
+var url = SimpleTest.getTestFileURL("script_createFile.js");
+var script = SpecialPowers.loadChromeScript(url);
+
+function onOpened(message) {
+  function workerCode() {
+    onmessage = function(e) {
+      self.close();
+      var fr = new FileReaderSync();
+      self.postMessage(fr.readAsText(e.data));
+    }
+  }
+
+  var b = new Blob([workerCode+'workerCode();']);
+  var w = new Worker(URL.createObjectURL(b));
+  w.onmessage = function(e) {
+    is(e.data, "Hello world!", "The blob content is OK!");
+    SimpleTest.finish();
+  }
+
+  w.postMessage(message.data);
+}
+
+script.addMessageListener("nonEmptyFile.opened", onOpened);
+script.sendAsyncMessage("nonEmptyFile.open");
+
+SimpleTest.waitForExplicitFinish();
+
+  </script>
+</body>
+</html>