Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / net / spdy / spdy_write_queue.cc
index 3a4eef5..05b965d 100644 (file)
@@ -5,8 +5,10 @@
 #include "net/spdy/spdy_write_queue.h"
 
 #include <cstddef>
+#include <vector>
 
 #include "base/logging.h"
+#include "base/stl_util.h"
 #include "net/spdy/spdy_buffer.h"
 #include "net/spdy/spdy_buffer_producer.h"
 #include "net/spdy/spdy_stream.h"
@@ -26,7 +28,7 @@ SpdyWriteQueue::PendingWrite::PendingWrite(
 
 SpdyWriteQueue::PendingWrite::~PendingWrite() {}
 
-SpdyWriteQueue::SpdyWriteQueue() {}
+SpdyWriteQueue::SpdyWriteQueue() : removing_writes_(false) {}
 
 SpdyWriteQueue::~SpdyWriteQueue() {
   Clear();
@@ -44,6 +46,7 @@ void SpdyWriteQueue::Enqueue(RequestPriority priority,
                              SpdyFrameType frame_type,
                              scoped_ptr<SpdyBufferProducer> frame_producer,
                              const base::WeakPtr<SpdyStream>& stream) {
+  CHECK(!removing_writes_);
   CHECK_GE(priority, MINIMUM_PRIORITY);
   CHECK_LE(priority, MAXIMUM_PRIORITY);
   if (stream.get())
@@ -55,6 +58,7 @@ void SpdyWriteQueue::Enqueue(RequestPriority priority,
 bool SpdyWriteQueue::Dequeue(SpdyFrameType* frame_type,
                              scoped_ptr<SpdyBufferProducer>* frame_producer,
                              base::WeakPtr<SpdyStream>* stream) {
+  CHECK(!removing_writes_);
   for (int i = MAXIMUM_PRIORITY; i >= MINIMUM_PRIORITY; --i) {
     if (!queue_[i].empty()) {
       PendingWrite pending_write = queue_[i].front();
@@ -72,6 +76,8 @@ bool SpdyWriteQueue::Dequeue(SpdyFrameType* frame_type,
 
 void SpdyWriteQueue::RemovePendingWritesForStream(
     const base::WeakPtr<SpdyStream>& stream) {
+  CHECK(!removing_writes_);
+  removing_writes_ = true;
   RequestPriority priority = stream->priority();
   CHECK_GE(priority, MINIMUM_PRIORITY);
   CHECK_LE(priority, MAXIMUM_PRIORITY);
@@ -90,23 +96,33 @@ void SpdyWriteQueue::RemovePendingWritesForStream(
   }
 #endif
 
+  // Defer deletion until queue iteration is complete, as
+  // SpdyBuffer::~SpdyBuffer() can result in callbacks into SpdyWriteQueue.
+  std::vector<SpdyBufferProducer*> erased_buffer_producers;
+
   // Do the actual deletion and removal, preserving FIFO-ness.
   std::deque<PendingWrite>* queue = &queue_[priority];
   std::deque<PendingWrite>::iterator out_it = queue->begin();
   for (std::deque<PendingWrite>::const_iterator it = queue->begin();
        it != queue->end(); ++it) {
     if (it->stream.get() == stream.get()) {
-      delete it->frame_producer;
+      erased_buffer_producers.push_back(it->frame_producer);
     } else {
       *out_it = *it;
       ++out_it;
     }
   }
   queue->erase(out_it, queue->end());
+  removing_writes_ = false;
+  STLDeleteElements(&erased_buffer_producers);  // Invokes callbacks.
 }
 
 void SpdyWriteQueue::RemovePendingWritesForStreamsAfter(
     SpdyStreamId last_good_stream_id) {
+  CHECK(!removing_writes_);
+  removing_writes_ = true;
+  std::vector<SpdyBufferProducer*> erased_buffer_producers;
+
   for (int i = MINIMUM_PRIORITY; i <= MAXIMUM_PRIORITY; ++i) {
     // Do the actual deletion and removal, preserving FIFO-ness.
     std::deque<PendingWrite>* queue = &queue_[i];
@@ -115,7 +131,7 @@ void SpdyWriteQueue::RemovePendingWritesForStreamsAfter(
          it != queue->end(); ++it) {
       if (it->stream.get() && (it->stream->stream_id() > last_good_stream_id ||
                                it->stream->stream_id() == 0)) {
-        delete it->frame_producer;
+        erased_buffer_producers.push_back(it->frame_producer);
       } else {
         *out_it = *it;
         ++out_it;
@@ -123,16 +139,24 @@ void SpdyWriteQueue::RemovePendingWritesForStreamsAfter(
     }
     queue->erase(out_it, queue->end());
   }
+  removing_writes_ = false;
+  STLDeleteElements(&erased_buffer_producers);  // Invokes callbacks.
 }
 
 void SpdyWriteQueue::Clear() {
+  CHECK(!removing_writes_);
+  removing_writes_ = true;
+  std::vector<SpdyBufferProducer*> erased_buffer_producers;
+
   for (int i = MINIMUM_PRIORITY; i <= MAXIMUM_PRIORITY; ++i) {
     for (std::deque<PendingWrite>::iterator it = queue_[i].begin();
          it != queue_[i].end(); ++it) {
-      delete it->frame_producer;
+      erased_buffer_producers.push_back(it->frame_producer);
     }
     queue_[i].clear();
   }
+  removing_writes_ = false;
+  STLDeleteElements(&erased_buffer_producers);  // Invokes callbacks.
 }
 
 }  // namespace net