summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMonty Brandenberg <monty@lindenlab.com>2012-07-03 13:06:46 -0400
committerMonty Brandenberg <monty@lindenlab.com>2012-07-03 13:06:46 -0400
commit2d7b7de20327a40be12a620debaae9917af16cd6 (patch)
tree501d8a8f5213466c061d31bafc0d43ca9f0657b6
parent7997a9c4e58f67a8cf4d13cdc3e2a1b536bc1e4d (diff)
More integration work for texture fetch timeouts.
The fetch state machine received a new timeout during the WAIT_HTTP_REQ state. For the integration, rather than jump the state to done, we issue a request cancel and let the notification plumbing do the rest without any race conditions or special-case logic.
-rw-r--r--indra/llcorehttp/_httplibcurl.cpp24
-rw-r--r--indra/llcorehttp/_httplibcurl.h3
-rw-r--r--indra/llcorehttp/_httpopcancel.cpp6
-rw-r--r--indra/llcorehttp/_httppolicy.cpp49
-rw-r--r--indra/llcorehttp/_httppolicy.h3
-rw-r--r--indra/llcorehttp/_httpservice.cpp25
-rw-r--r--indra/llcorehttp/_httpservice.h8
-rwxr-xr-xindra/newview/lltexturefetch.cpp20
8 files changed, 133 insertions, 5 deletions
diff --git a/indra/llcorehttp/_httplibcurl.cpp b/indra/llcorehttp/_httplibcurl.cpp
index 39abca12c5..3c69ae1c96 100644
--- a/indra/llcorehttp/_httplibcurl.cpp
+++ b/indra/llcorehttp/_httplibcurl.cpp
@@ -189,6 +189,30 @@ void HttpLibcurl::addOp(HttpOpRequest * op)
}
+// Implements the transport part of any cancel operation.
+// See if the handle is an active operation and if so,
+// use the more complicated transport-based cancelation
+// method to kill the request.
+bool HttpLibcurl::cancel(HttpHandle handle)
+{
+ HttpOpRequest * op(static_cast<HttpOpRequest *>(handle));
+ active_set_t::iterator it(mActiveOps.find(op));
+ if (mActiveOps.end() == it)
+ {
+ return false;
+ }
+
+ // Cancel request
+ cancelRequest(op);
+
+ // Drop references
+ mActiveOps.erase(it);
+ op->release();
+
+ return true;
+}
+
+
// *NOTE: cancelRequest logic parallels completeRequest logic.
// Keep them synchronized as necessary. Caller is expected to
// remove to op from the active list and release the op *after*
diff --git a/indra/llcorehttp/_httplibcurl.h b/indra/llcorehttp/_httplibcurl.h
index 69f7bb2b6d..53972b1ffa 100644
--- a/indra/llcorehttp/_httplibcurl.h
+++ b/indra/llcorehttp/_httplibcurl.h
@@ -85,6 +85,9 @@ public:
int getActiveCount() const;
int getActiveCountInClass(int policy_class) const;
+ // Shadows HttpService's method
+ bool cancel(HttpHandle handle);
+
protected:
/// Invoked when libcurl has indicated a request has been processed
/// to completion and we need to move the request to a new state.
diff --git a/indra/llcorehttp/_httpopcancel.cpp b/indra/llcorehttp/_httpopcancel.cpp
index ad624d2e57..5c1f484109 100644
--- a/indra/llcorehttp/_httpopcancel.cpp
+++ b/indra/llcorehttp/_httpopcancel.cpp
@@ -61,7 +61,11 @@ HttpOpCancel::~HttpOpCancel()
void HttpOpCancel::stageFromRequest(HttpService * service)
{
- // *FIXME: Need cancel functionality into services
+ if (! service->cancel(mHandle))
+ {
+ mStatus = HttpStatus(HttpStatus::LLCORE, HE_HANDLE_NOT_FOUND);
+ }
+
addAsReply();
}
diff --git a/indra/llcorehttp/_httppolicy.cpp b/indra/llcorehttp/_httppolicy.cpp
index 4350ff617b..1b10805b72 100644
--- a/indra/llcorehttp/_httppolicy.cpp
+++ b/indra/llcorehttp/_httppolicy.cpp
@@ -231,9 +231,12 @@ bool HttpPolicy::changePriority(HttpHandle handle, HttpRequest::priority_t prior
for (int policy_class(0); policy_class < mActiveClasses; ++policy_class)
{
State & state(mState[policy_class]);
- HttpReadyQueue::container_type & c(state.mReadyQueue.get_container());
-
+ // We don't scan retry queue because a priority change there
+ // is meaningless. The request will be issued based on retry
+ // intervals not priority value, which is now moot.
+
// Scan ready queue for requests that match policy
+ HttpReadyQueue::container_type & c(state.mReadyQueue.get_container());
for (HttpReadyQueue::container_type::iterator iter(c.begin()); c.end() != iter;)
{
HttpReadyQueue::container_type::iterator cur(iter++);
@@ -253,6 +256,48 @@ bool HttpPolicy::changePriority(HttpHandle handle, HttpRequest::priority_t prior
}
+bool HttpPolicy::cancel(HttpHandle handle)
+{
+ for (int policy_class(0); policy_class < mActiveClasses; ++policy_class)
+ {
+ State & state(mState[policy_class]);
+
+ // Scan retry queue
+ HttpRetryQueue::container_type & c1(state.mRetryQueue.get_container());
+ for (HttpRetryQueue::container_type::iterator iter(c1.begin()); c1.end() != iter;)
+ {
+ HttpRetryQueue::container_type::iterator cur(iter++);
+
+ if (static_cast<HttpHandle>(*cur) == handle)
+ {
+ HttpOpRequest * op(*cur);
+ c1.erase(cur); // All iterators are now invalidated
+ op->cancel();
+ op->release();
+ return true;
+ }
+ }
+
+ // Scan ready queue
+ HttpReadyQueue::container_type & c2(state.mReadyQueue.get_container());
+ for (HttpReadyQueue::container_type::iterator iter(c2.begin()); c2.end() != iter;)
+ {
+ HttpReadyQueue::container_type::iterator cur(iter++);
+
+ if (static_cast<HttpHandle>(*cur) == handle)
+ {
+ HttpOpRequest * op(*cur);
+ c2.erase(cur); // All iterators are now invalidated
+ op->cancel();
+ op->release();
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
bool HttpPolicy::stageAfterCompletion(HttpOpRequest * op)
{
static const HttpStatus cant_connect(HttpStatus::EXT_CURL_EASY, CURLE_COULDNT_CONNECT);
diff --git a/indra/llcorehttp/_httppolicy.h b/indra/llcorehttp/_httppolicy.h
index 90bb3b571d..a02bf084c1 100644
--- a/indra/llcorehttp/_httppolicy.h
+++ b/indra/llcorehttp/_httppolicy.h
@@ -92,6 +92,9 @@ public:
// Shadows HttpService's method
bool changePriority(HttpHandle handle, HttpRequest::priority_t priority);
+ // Shadows HttpService's method as well
+ bool cancel(HttpHandle handle);
+
/// When transport is finished with an op and takes it off the
/// active queue, it is delivered here for dispatch. Policy
/// may send it back to the ready/retry queues if it needs another
diff --git a/indra/llcorehttp/_httpservice.cpp b/indra/llcorehttp/_httpservice.cpp
index 92c15b5b8f..f7d9813db0 100644
--- a/indra/llcorehttp/_httpservice.cpp
+++ b/indra/llcorehttp/_httpservice.cpp
@@ -219,6 +219,31 @@ bool HttpService::changePriority(HttpHandle handle, HttpRequest::priority_t prio
}
+ /// Try to find the given request handle on any of the request
+ /// queues and cancel the operation.
+ ///
+ /// @return True if the request was canceled.
+ ///
+ /// Threading: callable by worker thread.
+bool HttpService::cancel(HttpHandle handle)
+{
+ bool canceled(false);
+
+ // Request can't be on request queue so skip that.
+
+ // Check the policy component's queues first
+ canceled = mPolicy->cancel(handle);
+
+ if (! canceled)
+ {
+ // If that didn't work, check transport's.
+ canceled = mTransport->cancel(handle);
+ }
+
+ return canceled;
+}
+
+
/// Threading: callable by worker thread.
void HttpService::shutdown()
{
diff --git a/indra/llcorehttp/_httpservice.h b/indra/llcorehttp/_httpservice.h
index d67e6e95a5..d24c497ca9 100644
--- a/indra/llcorehttp/_httpservice.h
+++ b/indra/llcorehttp/_httpservice.h
@@ -154,6 +154,14 @@ public:
/// Threading: callable by worker thread.
bool changePriority(HttpHandle handle, HttpRequest::priority_t priority);
+ /// Try to find the given request handle on any of the request
+ /// queues and cancel the operation.
+ ///
+ /// @return True if the request was found and canceled.
+ ///
+ /// Threading: callable by worker thread.
+ bool cancel(HttpHandle handle);
+
/// Threading: callable by worker thread.
HttpPolicy & getPolicy()
{
diff --git a/indra/newview/lltexturefetch.cpp b/indra/newview/lltexturefetch.cpp
index 36b878d6f2..b30b25e543 100755
--- a/indra/newview/lltexturefetch.cpp
+++ b/indra/newview/lltexturefetch.cpp
@@ -1560,8 +1560,24 @@ bool LLTextureFetchWorker::doWork(S32 param)
if(FETCHING_TIMEOUT < mRequestedTimer.getElapsedTimeF32())
{
//timeout, abort.
- mState = DONE;
- return true;
+ LL_WARNS("Texture") << "Fetch of texture " << mID << " timed out after "
+ << mRequestedTimer.getElapsedTimeF32()
+ << " seconds. Canceling request." << LL_ENDL;
+
+ if (LLCORE_HTTP_HANDLE_INVALID != mHttpHandle)
+ {
+ // Issue cancel on any outstanding request. Asynchronous
+ // so cancel may not actually take effect if operation is
+ // complete & queued. Either way, notification will
+ // complete and the request can be transitioned.
+ mFetcher->mHttpRequest->requestCancel(mHttpHandle, NULL);
+ }
+ else
+ {
+ // Shouldn't happen but if it does, cancel quickly.
+ mState = DONE;
+ return true;
+ }
}
setPriority(LLWorkerThread::PRIORITY_LOW | mWorkPriority);