зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1530190. Allow nsIconChannel::Open to work on Windows. r=aosmond
As stated in other patches in this bug, the system call has to happen off main thread, and it has to always be on the same thread. So we dispatch the task to that thread and synchronously wait on the main thread for it to finish. Differential Revision: https://phabricator.services.mozilla.com/D29626
This commit is contained in:
Родитель
2fb442368f
Коммит
1ff1a4a196
|
@ -5,6 +5,7 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "mozilla/ArrayUtils.h"
|
||||
#include "mozilla/Monitor.h"
|
||||
|
||||
#include "nsIconChannel.h"
|
||||
#include "nsIIconURI.h"
|
||||
|
@ -99,6 +100,61 @@ NS_IMETHODIMP nsIconChannel::IconAsyncOpenTask::Run() {
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
class nsIconChannel::IconSyncOpenTask final : public Runnable {
|
||||
public:
|
||||
IconSyncOpenTask(nsIconChannel* aChannel, nsIEventTarget* aTarget,
|
||||
nsCOMPtr<nsIFile>&& aLocalFile, nsAutoString& aPath,
|
||||
UINT aInfoFlags)
|
||||
: Runnable("IconSyncOpenTask"),
|
||||
mMonitor("IconSyncOpenTask"),
|
||||
mDone(false),
|
||||
mChannel(aChannel),
|
||||
mTarget(aTarget),
|
||||
mLocalFile(std::move(aLocalFile)),
|
||||
mPath(aPath),
|
||||
mInfoFlags(aInfoFlags),
|
||||
mHIcon(nullptr),
|
||||
mRv(NS_OK) {}
|
||||
|
||||
NS_IMETHOD Run() override;
|
||||
|
||||
Monitor& GetMonitor() { return mMonitor; }
|
||||
bool Done() const {
|
||||
mMonitor.AssertCurrentThreadOwns();
|
||||
return mDone;
|
||||
}
|
||||
HICON GetHIcon() const {
|
||||
mMonitor.AssertCurrentThreadOwns();
|
||||
return mHIcon;
|
||||
}
|
||||
nsresult GetRv() const {
|
||||
mMonitor.AssertCurrentThreadOwns();
|
||||
return mRv;
|
||||
}
|
||||
|
||||
private:
|
||||
Monitor mMonitor;
|
||||
bool mDone;
|
||||
// Parameters in
|
||||
RefPtr<nsIconChannel> mChannel;
|
||||
nsCOMPtr<nsIEventTarget> mTarget;
|
||||
nsCOMPtr<nsIFile> mLocalFile;
|
||||
nsAutoString mPath;
|
||||
UINT mInfoFlags;
|
||||
// Return values
|
||||
HICON mHIcon;
|
||||
nsresult mRv;
|
||||
};
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsIconChannel::IconSyncOpenTask::Run() {
|
||||
MonitorAutoLock lock(mMonitor);
|
||||
mRv = mChannel->GetHIconFromFile(mLocalFile, mPath, mInfoFlags, &mHIcon);
|
||||
mDone = true;
|
||||
mMonitor.NotifyAll();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// nsIconChannel methods
|
||||
nsIconChannel::nsIconChannel() {}
|
||||
|
||||
|
@ -425,7 +481,19 @@ nsresult nsIconChannel::GetHIconFromFile(bool aNonBlocking, HICON* hIcon) {
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
return GetHIconFromFile(localFile, filePath, infoFlags, hIcon);
|
||||
// We cannot call SHGetFileInfo on more than one thread (at a time), so it
|
||||
// must be called on the same thread every time, even now when we need sync
|
||||
// behaviour. So we synchronously wait on the other thread to finish.
|
||||
RefPtr<nsIEventTarget> target = DecodePool::Singleton()->GetIOEventTarget();
|
||||
RefPtr<IconSyncOpenTask> task = new IconSyncOpenTask(
|
||||
this, mListenerTarget, std::move(localFile), filePath, infoFlags);
|
||||
MonitorAutoLock lock(task->GetMonitor());
|
||||
target->Dispatch(task, NS_DISPATCH_NORMAL);
|
||||
do {
|
||||
task->GetMonitor().Wait();
|
||||
} while (!task->Done());
|
||||
*hIcon = task->GetHIcon();
|
||||
return task->GetRv();
|
||||
}
|
||||
|
||||
nsresult nsIconChannel::GetHIconFromFile(nsIFile* aLocalFile,
|
||||
|
|
|
@ -42,6 +42,7 @@ class nsIconChannel final : public nsIChannel, public nsIStreamListener {
|
|||
|
||||
protected:
|
||||
class IconAsyncOpenTask;
|
||||
class IconSyncOpenTask;
|
||||
|
||||
void OnAsyncError(nsresult aStatus);
|
||||
void FinishAsyncOpen(HICON aIcon, nsresult aStatus);
|
||||
|
|
Загрузка…
Ссылка в новой задаче