summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorIain Merrick <husky@google.com>2010-08-12 16:00:40 +0100
committerIain Merrick <husky@google.com>2010-08-13 18:41:53 +0100
commita01792f8060881461b672472ba3dfdd77044e0a5 (patch)
tree35c7b09d44b07d85d3236984c2d9b3569a40e275
parentbf0ea53811034ee6502d88349868c53234cc55c2 (diff)
downloadexternal_webkit-a01792f8060881461b672472ba3dfdd77044e0a5.zip
external_webkit-a01792f8060881461b672472ba3dfdd77044e0a5.tar.gz
external_webkit-a01792f8060881461b672472ba3dfdd77044e0a5.tar.bz2
Implement synchronous resource loading in Android.
Change-Id: I31c2c983f0b04db6fb5d2c4ccbe0ea837fc7db2b
-rw-r--r--WebKit/android/WebCoreSupport/WebRequest.cpp21
-rw-r--r--WebKit/android/WebCoreSupport/WebUrlLoaderClient.cpp76
-rw-r--r--WebKit/android/WebCoreSupport/WebUrlLoaderClient.h28
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;