mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 1187092 - Refactor the suspend process. r=jwwang
This commit is contained in:
parent
f77279b6c3
commit
c2936c3691
@ -69,12 +69,14 @@ ChannelMediaResource::ChannelMediaResource(MediaDecoder* aDecoder,
|
||||
nsIURI* aURI,
|
||||
const nsACString& aContentType)
|
||||
: BaseMediaResource(aDecoder, aChannel, aURI, aContentType),
|
||||
mOffset(0), mSuspendCount(0),
|
||||
mReopenOnError(false), mIgnoreClose(false),
|
||||
mOffset(0),
|
||||
mReopenOnError(false),
|
||||
mIgnoreClose(false),
|
||||
mCacheStream(this),
|
||||
mLock("ChannelMediaResource.mLock"),
|
||||
mIgnoreResume(false),
|
||||
mIsTransportSeekable(true)
|
||||
mIsTransportSeekable(true),
|
||||
mSuspendAgent(mChannel)
|
||||
{
|
||||
if (!gMediaResourceLog) {
|
||||
gMediaResourceLog = PR_NewLogModule("MediaResource");
|
||||
@ -317,13 +319,7 @@ ChannelMediaResource::OnStartRequest(nsIRequest* aRequest)
|
||||
mReopenOnError = false;
|
||||
mIgnoreClose = false;
|
||||
|
||||
if (mSuspendCount > 0) {
|
||||
// Re-suspend the channel if it needs to be suspended
|
||||
// No need to call PossiblySuspend here since the channel is
|
||||
// definitely in the right state for us in OnStartRequest.
|
||||
mChannel->Suspend();
|
||||
mIgnoreResume = false;
|
||||
}
|
||||
mSuspendAgent.UpdateSuspendedStatusIfNeeded();
|
||||
|
||||
// Fires an initial progress event.
|
||||
owner->DownloadProgressed();
|
||||
@ -389,7 +385,7 @@ nsresult
|
||||
ChannelMediaResource::OnStopRequest(nsIRequest* aRequest, nsresult aStatus)
|
||||
{
|
||||
NS_ASSERTION(mChannel.get() == aRequest, "Wrong channel!");
|
||||
NS_ASSERTION(mSuspendCount == 0,
|
||||
NS_ASSERTION(!mSuspendAgent.IsSuspended(),
|
||||
"How can OnStopRequest fire while we're suspended?");
|
||||
|
||||
{
|
||||
@ -439,6 +435,7 @@ ChannelMediaResource::OnChannelRedirect(nsIChannel* aOld, nsIChannel* aNew,
|
||||
uint32_t aFlags)
|
||||
{
|
||||
mChannel = aNew;
|
||||
mSuspendAgent.NotifyChannelOpened(mChannel);
|
||||
return SetupChannelHeaders();
|
||||
}
|
||||
|
||||
@ -678,7 +675,7 @@ already_AddRefed<MediaResource> ChannelMediaResource::CloneData(MediaDecoder* aD
|
||||
// which will recreate the channel. This way, if all of the media data
|
||||
// is already in the cache we don't create an unnecessary HTTP channel
|
||||
// and perform a useless HTTP transaction.
|
||||
resource->mSuspendCount = 1;
|
||||
resource->mSuspendAgent.Suspend();
|
||||
resource->mCacheStream.InitAsClone(&mCacheStream);
|
||||
resource->mChannelStatistics = new MediaChannelStatistics(mChannelStatistics);
|
||||
resource->mChannelStatistics->Stop();
|
||||
@ -701,10 +698,7 @@ void ChannelMediaResource::CloseChannel()
|
||||
}
|
||||
|
||||
if (mChannel) {
|
||||
if (mSuspendCount > 0) {
|
||||
// Resume the channel before we cancel it
|
||||
PossiblyResume();
|
||||
}
|
||||
mSuspendAgent.NotifyChannelClosing();
|
||||
// The status we use here won't be passed to the decoder, since
|
||||
// we've already revoked the listener. It can however be passed
|
||||
// to nsDocumentViewer::LoadComplete if our channel is the one
|
||||
@ -790,29 +784,27 @@ void ChannelMediaResource::Suspend(bool aCloseImmediately)
|
||||
return;
|
||||
}
|
||||
|
||||
if (mChannel) {
|
||||
if (aCloseImmediately && mCacheStream.IsTransportSeekable()) {
|
||||
if (mChannel && aCloseImmediately && mCacheStream.IsTransportSeekable()) {
|
||||
// Kill off our channel right now, but don't tell anyone about it.
|
||||
mIgnoreClose = true;
|
||||
CloseChannel();
|
||||
element->DownloadSuspended();
|
||||
} else if (mSuspendCount == 0) {
|
||||
}
|
||||
|
||||
if (mSuspendAgent.Suspend()) {
|
||||
if (mChannel) {
|
||||
{
|
||||
MutexAutoLock lock(mLock);
|
||||
mChannelStatistics->Stop();
|
||||
}
|
||||
PossiblySuspend();
|
||||
element->DownloadSuspended();
|
||||
}
|
||||
}
|
||||
|
||||
++mSuspendCount;
|
||||
}
|
||||
|
||||
void ChannelMediaResource::Resume()
|
||||
{
|
||||
NS_ASSERTION(NS_IsMainThread(), "Don't call on non-main thread");
|
||||
NS_ASSERTION(mSuspendCount > 0, "Too many resumes!");
|
||||
|
||||
MediaDecoderOwner* owner = mDecoder->GetMediaOwner();
|
||||
if (!owner) {
|
||||
@ -825,9 +817,7 @@ void ChannelMediaResource::Resume()
|
||||
return;
|
||||
}
|
||||
|
||||
NS_ASSERTION(mSuspendCount > 0, "Resume without previous Suspend!");
|
||||
--mSuspendCount;
|
||||
if (mSuspendCount == 0) {
|
||||
if (mSuspendAgent.Resume()) {
|
||||
if (mChannel) {
|
||||
// Just wake up our existing channel
|
||||
{
|
||||
@ -837,7 +827,6 @@ void ChannelMediaResource::Resume()
|
||||
// if an error occurs after Resume, assume it's because the server
|
||||
// timed out the connection and we should reopen it.
|
||||
mReopenOnError = true;
|
||||
PossiblyResume();
|
||||
element->DownloadResumed();
|
||||
} else {
|
||||
int64_t totalLength = mCacheStream.GetLength();
|
||||
@ -909,6 +898,7 @@ ChannelMediaResource::RecreateChannel()
|
||||
NS_ASSERTION(!GetContentType().IsEmpty(),
|
||||
"When recreating a channel, we should know the Content-Type.");
|
||||
mChannel->SetContentType(GetContentType());
|
||||
mSuspendAgent.NotifyChannelOpened(mChannel);
|
||||
|
||||
// Tell the cache to reset the download status when the channel is reopened.
|
||||
mCacheStream.NotifyChannelRecreated();
|
||||
@ -1000,21 +990,19 @@ ChannelMediaResource::CacheClientSeek(int64_t aOffset, bool aResume)
|
||||
|
||||
CloseChannel();
|
||||
|
||||
if (aResume) {
|
||||
NS_ASSERTION(mSuspendCount > 0, "Too many resumes!");
|
||||
// No need to mess with the channel, since we're making a new one
|
||||
--mSuspendCount;
|
||||
}
|
||||
|
||||
mOffset = aOffset;
|
||||
|
||||
// Don't report close of the channel because the channel is not closed for
|
||||
// download ended, but for internal changes in the read position.
|
||||
mIgnoreClose = true;
|
||||
|
||||
if (aResume) {
|
||||
mSuspendAgent.Resume();
|
||||
}
|
||||
|
||||
// Don't create a new channel if we are still suspended. The channel will
|
||||
// be recreated when we are resumed.
|
||||
if (mSuspendCount > 0) {
|
||||
if (mSuspendAgent.IsSuspended()) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@ -1091,7 +1079,7 @@ ChannelMediaResource::IsSuspendedByCache()
|
||||
bool
|
||||
ChannelMediaResource::IsSuspended()
|
||||
{
|
||||
return mSuspendCount > 0;
|
||||
return mSuspendAgent.IsSuspended();
|
||||
}
|
||||
|
||||
void
|
||||
@ -1131,29 +1119,80 @@ ChannelMediaResource::GetLength()
|
||||
return mCacheStream.GetLength();
|
||||
}
|
||||
|
||||
void
|
||||
ChannelMediaResource::PossiblySuspend()
|
||||
// ChannelSuspendAgent
|
||||
|
||||
bool
|
||||
ChannelSuspendAgent::Suspend()
|
||||
{
|
||||
SuspendInternal();
|
||||
return (++mSuspendCount == 1);
|
||||
}
|
||||
|
||||
void
|
||||
ChannelSuspendAgent::SuspendInternal()
|
||||
{
|
||||
if (mChannel) {
|
||||
bool isPending = false;
|
||||
nsresult rv = mChannel->IsPending(&isPending);
|
||||
if (NS_SUCCEEDED(rv) && isPending) {
|
||||
if (NS_SUCCEEDED(rv) && isPending && !mIsChannelSuspended) {
|
||||
mChannel->Suspend();
|
||||
mIgnoreResume = false;
|
||||
} else {
|
||||
mIgnoreResume = true;
|
||||
mIsChannelSuspended = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
ChannelSuspendAgent::Resume()
|
||||
{
|
||||
MOZ_ASSERT(IsSuspended(), "Resume without suspend!");
|
||||
--mSuspendCount;
|
||||
|
||||
if (mSuspendCount == 0) {
|
||||
if (mChannel && mIsChannelSuspended) {
|
||||
mChannel->Resume();
|
||||
mIsChannelSuspended = false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
ChannelSuspendAgent::UpdateSuspendedStatusIfNeeded()
|
||||
{
|
||||
if (!mIsChannelSuspended && IsSuspended()) {
|
||||
SuspendInternal();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ChannelMediaResource::PossiblyResume()
|
||||
ChannelSuspendAgent::NotifyChannelOpened(nsIChannel* aChannel)
|
||||
{
|
||||
if (!mIgnoreResume) {
|
||||
mChannel->Resume();
|
||||
} else {
|
||||
mIgnoreResume = false;
|
||||
}
|
||||
MOZ_ASSERT(aChannel);
|
||||
mChannel = aChannel;
|
||||
}
|
||||
|
||||
void
|
||||
ChannelSuspendAgent::NotifyChannelClosing()
|
||||
{
|
||||
MOZ_ASSERT(mChannel);
|
||||
// Before close the channel, it need to be resumed to make sure its internal
|
||||
// state is correct. Besides, We need to suspend the channel after recreating.
|
||||
if (mIsChannelSuspended) {
|
||||
mChannel->Resume();
|
||||
mIsChannelSuspended = false;
|
||||
}
|
||||
mChannel = nullptr;
|
||||
}
|
||||
|
||||
bool
|
||||
ChannelSuspendAgent::IsSuspended()
|
||||
{
|
||||
return (mSuspendCount > 0);
|
||||
}
|
||||
|
||||
// FileMediaResource
|
||||
|
||||
class FileMediaResource : public BaseMediaResource
|
||||
{
|
||||
public:
|
||||
|
@ -537,6 +537,47 @@ protected:
|
||||
bool mLoadInBackground;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* This class is responsible for managing the suspend count and report suspend
|
||||
* status of channel.
|
||||
**/
|
||||
class ChannelSuspendAgent {
|
||||
public:
|
||||
explicit ChannelSuspendAgent(nsIChannel* aChannel)
|
||||
: mChannel(aChannel),
|
||||
mSuspendCount(0),
|
||||
mIsChannelSuspended(false)
|
||||
{}
|
||||
|
||||
// True when the channel has been suspended or needs to be suspended.
|
||||
bool IsSuspended();
|
||||
|
||||
// Return true when the channel is logically suspended, i.e. the suspend
|
||||
// count goes from 0 to 1.
|
||||
bool Suspend();
|
||||
|
||||
// Return true only when the suspend count is equal to zero.
|
||||
bool Resume();
|
||||
|
||||
// Call after opening channel, set channel and check whether the channel
|
||||
// needs to be suspended.
|
||||
void NotifyChannelOpened(nsIChannel* aChannel);
|
||||
|
||||
// Call before closing channel, reset the channel internal status if needed.
|
||||
void NotifyChannelClosing();
|
||||
|
||||
// Check whether we need to suspend the channel.
|
||||
void UpdateSuspendedStatusIfNeeded();
|
||||
private:
|
||||
// Only suspends channel but not changes the suspend count.
|
||||
void SuspendInternal();
|
||||
|
||||
nsIChannel* mChannel;
|
||||
Atomic<uint32_t> mSuspendCount;
|
||||
bool mIsChannelSuspended;
|
||||
};
|
||||
|
||||
/**
|
||||
* This is the MediaResource implementation that wraps Necko channels.
|
||||
* Much of its functionality is actually delegated to MediaCache via
|
||||
@ -707,21 +748,12 @@ protected:
|
||||
uint32_t aCount,
|
||||
uint32_t *aWriteCount);
|
||||
|
||||
// Suspend the channel only if the channels is currently downloading data.
|
||||
// If it isn't we set a flag, mIgnoreResume, so that PossiblyResume knows
|
||||
// whether to acutually resume or not.
|
||||
void PossiblySuspend();
|
||||
|
||||
// Resume from a suspend if we actually suspended (See PossiblySuspend).
|
||||
void PossiblyResume();
|
||||
|
||||
// Main thread access only
|
||||
int64_t mOffset;
|
||||
nsRefPtr<Listener> mListener;
|
||||
// A data received event for the decoder that has been dispatched but has
|
||||
// not yet been processed.
|
||||
nsRevocableEventPtr<nsRunnableMethod<ChannelMediaResource, void, false> > mDataReceivedEvent;
|
||||
Atomic<uint32_t> mSuspendCount;
|
||||
// When this flag is set, if we get a network error we should silently
|
||||
// reopen the stream.
|
||||
bool mReopenOnError;
|
||||
@ -747,6 +779,8 @@ protected:
|
||||
// True if the stream can seek into unbuffered ranged, i.e. if the
|
||||
// connection supports byte range requests.
|
||||
bool mIsTransportSeekable;
|
||||
|
||||
ChannelSuspendAgent mSuspendAgent;
|
||||
};
|
||||
|
||||
/**
|
||||
|
Loading…
Reference in New Issue
Block a user