diff options
author | Iain Merrick <husky@google.com> | 2010-08-12 16:00:40 +0100 |
---|---|---|
committer | Iain Merrick <husky@google.com> | 2010-08-13 18:41:53 +0100 |
commit | a01792f8060881461b672472ba3dfdd77044e0a5 (patch) | |
tree | 35c7b09d44b07d85d3236984c2d9b3569a40e275 /WebKit/android | |
parent | bf0ea53811034ee6502d88349868c53234cc55c2 (diff) | |
download | external_webkit-a01792f8060881461b672472ba3dfdd77044e0a5.zip external_webkit-a01792f8060881461b672472ba3dfdd77044e0a5.tar.gz external_webkit-a01792f8060881461b672472ba3dfdd77044e0a5.tar.bz2 |
Implement synchronous resource loading in Android.
Change-Id: I31c2c983f0b04db6fb5d2c4ccbe0ea837fc7db2b
Diffstat (limited to 'WebKit/android')
-rw-r--r-- | WebKit/android/WebCoreSupport/WebRequest.cpp | 21 | ||||
-rw-r--r-- | WebKit/android/WebCoreSupport/WebUrlLoaderClient.cpp | 76 | ||||
-rw-r--r-- | WebKit/android/WebCoreSupport/WebUrlLoaderClient.h | 28 |
3 files changed, 103 insertions, 22 deletions
diff --git a/WebKit/android/WebCoreSupport/WebRequest.cpp b/WebKit/android/WebCoreSupport/WebRequest.cpp index 4030160..45318bc 100644 --- a/WebKit/android/WebCoreSupport/WebRequest.cpp +++ b/WebKit/android/WebCoreSupport/WebRequest.cpp @@ -49,7 +49,9 @@ namespace { const int kInitialReadBufSize = 32768; } -WebRequest::WebRequest(WebUrlLoaderClient* loader, WebResourceRequest webResourceRequest) : m_urlLoader(loader), m_request(0) +WebRequest::WebRequest(WebUrlLoaderClient* loader, WebResourceRequest webResourceRequest) + : m_urlLoader(loader) + , m_request(0) { GURL gurl(webResourceRequest.url()); m_request = new URLRequest(gurl, this); @@ -67,11 +69,11 @@ void WebRequest::finish(bool success) { if (success) { LoaderData* loaderData = new LoaderData(m_urlLoader); - callOnMainThread(WebUrlLoaderClient::didFinishLoading, loaderData); + m_urlLoader->maybeCallOnMainThread(WebUrlLoaderClient::didFinishLoading, loaderData); } else { WebResponse webResponse(m_request.get()); LoaderData* loaderData = new LoaderData(m_urlLoader, webResponse); - callOnMainThread(WebUrlLoaderClient::didFail, loaderData); + m_urlLoader->maybeCallOnMainThread(WebUrlLoaderClient::didFail, loaderData); } m_networkBuffer = 0; m_request = 0; @@ -110,11 +112,11 @@ void WebRequest::handleDataURL(GURL url) // weburlloader_impl.cc WebResponse webResponse(url.spec(), mimeType, data->size(), charset, 200); LoaderData* loaderResponse = new LoaderData(m_urlLoader, webResponse); - callOnMainThread(WebUrlLoaderClient::didReceiveResponse, loaderResponse); + m_urlLoader->maybeCallOnMainThread(WebUrlLoaderClient::didReceiveResponse, loaderResponse); if (!data->empty()) { LoaderData* loaderData = new LoaderData(m_urlLoader, data.leakPtr()); - callOnMainThread(WebUrlLoaderClient::didReceiveDataUrl, loaderData); + m_urlLoader->maybeCallOnMainThread(WebUrlLoaderClient::didReceiveDataUrl, loaderData); } } else { // handle the failed case @@ -123,7 +125,6 @@ void WebRequest::handleDataURL(GURL url) finish(true); } - // Called upon a server-initiated redirect. The delegate may call the // request's Cancel method to prevent the redirect from being followed. // Since there may be multiple chained redirects, there may also be more @@ -146,7 +147,7 @@ void WebRequest::OnReceivedRedirect(URLRequest* newRequest, const GURL& newUrl, WebResponse webResponse(newRequest); webResponse.setUrl(newUrl.spec()); LoaderData* ld = new LoaderData(m_urlLoader, webResponse); - callOnMainThread(WebUrlLoaderClient::willSendRequest, ld); + m_urlLoader->maybeCallOnMainThread(WebUrlLoaderClient::willSendRequest, ld); } else { // why would this happen? And what to do? } @@ -180,7 +181,7 @@ void WebRequest::OnResponseStarted(URLRequest* request) if (request && request->status().is_success()) { WebResponse webResponse(request); LoaderData* loaderData = new LoaderData(m_urlLoader, webResponse); - callOnMainThread(WebUrlLoaderClient::didReceiveResponse, loaderData); + m_urlLoader->maybeCallOnMainThread(WebUrlLoaderClient::didReceiveResponse, loaderData); // Start reading the response startReading(); @@ -205,7 +206,7 @@ void WebRequest::startReading() // Read ok, forward buffer to webcore m_networkBuffer->AddRef(); LoaderData* loaderData = new LoaderData(m_urlLoader, m_networkBuffer.get(), bytesRead); - callOnMainThread(WebUrlLoaderClient::didReceiveData, loaderData); + m_urlLoader->maybeCallOnMainThread(WebUrlLoaderClient::didReceiveData, loaderData); // m_networkBuffer->Release() on main thread m_networkBuffer = 0; } else if (m_request && m_request->status().is_io_pending()) { @@ -241,7 +242,7 @@ void WebRequest::OnReadCompleted(URLRequest* request, int bytesRead) m_networkBuffer->AddRef(); LoaderData* loaderData = new LoaderData(m_urlLoader, m_networkBuffer.get(), bytesRead); // m_networkBuffer->Release() on main thread - callOnMainThread(WebUrlLoaderClient::didReceiveData, loaderData); + m_urlLoader->maybeCallOnMainThread(WebUrlLoaderClient::didReceiveData, loaderData); m_networkBuffer = 0; // Get the rest of the data diff --git a/WebKit/android/WebCoreSupport/WebUrlLoaderClient.cpp b/WebKit/android/WebCoreSupport/WebUrlLoaderClient.cpp index bfb8eb7..33f94af 100644 --- a/WebKit/android/WebCoreSupport/WebUrlLoaderClient.cpp +++ b/WebKit/android/WebCoreSupport/WebUrlLoaderClient.cpp @@ -33,6 +33,8 @@ #include "WebRequest.h" #include "WebResourceRequest.h" +#include <base/condition_variable.h> +#include <base/lock.h> #include <base/thread.h> #include <net/base/io_buffer.h> @@ -66,12 +68,21 @@ base::Thread* WebUrlLoaderClient::ioThread() return networkThread; } +Lock* WebUrlLoaderClient::syncLock() { + static Lock s_syncLock; + return &s_syncLock; +} + +ConditionVariable* WebUrlLoaderClient::syncCondition() { + static ConditionVariable s_syncCondition(syncLock()); + return &s_syncCondition; +} + WebUrlLoaderClient::~WebUrlLoaderClient() { base::Thread* thread = ioThread(); if (thread) thread->message_loop()->ReleaseSoon(FROM_HERE, m_request); - } bool WebUrlLoaderClient::isActive() const @@ -85,7 +96,10 @@ bool WebUrlLoaderClient::isActive() const } WebUrlLoaderClient::WebUrlLoaderClient(WebCore::ResourceHandle* resourceHandle, const WebCore::ResourceRequest& resourceRequest) - : m_resourceHandle(resourceHandle), m_cancelling(false) + : m_resourceHandle(resourceHandle) + , m_cancelling(false) + , m_sync(false) + , m_finished(false) { WebResourceRequest webResourceRequest(resourceRequest); @@ -129,15 +143,40 @@ WebUrlLoaderClient::WebUrlLoaderClient(WebCore::ResourceHandle* resourceHandle, } } -bool WebUrlLoaderClient::start(bool /*sync*/) +bool WebUrlLoaderClient::start(bool sync) { base::Thread* thread = ioThread(); - if (thread) { - thread->message_loop()->PostTask(FROM_HERE, NewRunnableMethod(m_request, &WebRequest::start)); - return true; + if (!thread) { + return false; } - return false; + m_sync = sync; + if (m_sync) { + AutoLock autoLock(*syncLock()); + thread->message_loop()->PostTask(FROM_HERE, NewRunnableMethod(m_request, &WebRequest::start)); + + // Run callbacks until the queue is exhausted and m_finished is true. + while(!m_finished) { + while (!m_queue.empty()) { + Callback& callback = m_queue.front(); + CallbackFunction* function = callback.a; + void* context = callback.b; + (*function)(context); + m_queue.pop_front(); + } + if (m_queue.empty() && !m_finished) { + syncCondition()->Wait(); + } + } + + // This may be the last reference to us, so we may be deleted now. + // Don't access any more member variables after releasing this reference. + m_resourceHandle = 0; + } else { + // Asynchronous start. + thread->message_loop()->PostTask(FROM_HERE, NewRunnableMethod(m_request, &WebRequest::start)); + } + return true; } void WebUrlLoaderClient::cancel() @@ -151,9 +190,26 @@ void WebUrlLoaderClient::cancel() void WebUrlLoaderClient::finish() { - // This will probably cause this to be deleted as we are the only one holding a reference to - // m_resourceHandle, and it is holding the only reference to this. - m_resourceHandle = 0; + m_finished = true; + if (!m_sync) { + // This is the last reference to us, so we will be deleted now. + // We only release the reference here if start() was called asynchronously! + m_resourceHandle = 0; + } +} + +// This is called from the IO thread, and dispatches the callback to the main thread. +void WebUrlLoaderClient::maybeCallOnMainThread(CallbackFunction* function, void* context) { + if (m_sync) { + AutoLock autoLock(*syncLock()); + if (m_queue.empty()) { + syncCondition()->Broadcast(); + } + m_queue.push_back(Callback(function, context)); + } else { + // Let WebKit handle it. + callOnMainThread(function, context); + } } // Response methods diff --git a/WebKit/android/WebCoreSupport/WebUrlLoaderClient.h b/WebKit/android/WebCoreSupport/WebUrlLoaderClient.h index 399df08..4231d02 100644 --- a/WebKit/android/WebCoreSupport/WebUrlLoaderClient.h +++ b/WebKit/android/WebCoreSupport/WebUrlLoaderClient.h @@ -31,7 +31,12 @@ #include "WebUrlLoader.h" #include <base/ref_counted.h> +#include <base/tuple.h> #include <string> +#include <deque> + +class Lock; +class ConditionVariable; namespace base { class Thread; @@ -63,7 +68,13 @@ public: void downloadFile(); void pauseLoad(bool pause) {} // Android method, does nothing for now - // Called by WebRequest, should be forwarded to WebCore + typedef void CallbackFunction(void*); + + // This is called from the IO thread, and dispatches the callback to the main thread. + // (For asynchronous calls, we just delegate to WebKit's callOnMainThread.) + void maybeCallOnMainThread(CallbackFunction*, void* context); + + // Called by WebRequest (using maybeCallOnMainThread), should be forwarded to WebCore. static void didReceiveResponse(void*); static void didReceiveData(void*); static void didReceiveDataUrl(void*); @@ -75,6 +86,8 @@ private: void finish(); RefPtr<WebCore::ResourceHandle> m_resourceHandle; bool m_cancelling; + bool m_sync; + volatile bool m_finished; // Not an OwnPtr since it should be deleted on another thread WebRequest* m_request; @@ -84,9 +97,20 @@ private: // Check if a request is active bool isActive() const; + + // Mutex and condition variable used for synchronous requests. + // Note that these are static. This works because there's only one main thread. + static Lock* syncLock(); + static ConditionVariable* syncCondition(); + + typedef Tuple2<CallbackFunction*, void*> Callback; + typedef std::deque<Callback> CallbackQueue; + + // Queue of callbacks to be executed by the main thread. Must only be accessed inside mutex. + CallbackQueue m_queue; }; -// A struct to send more than one thing in a void*, needed for callOnMainThread +// A struct to send more than one thing in a void*, needed for maybeCallOnMainThread struct LoaderData { net::IOBuffer* buffer; WebUrlLoaderClient* loader; |