#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"
SpdyWriteQueue::PendingWrite::~PendingWrite() {}
-SpdyWriteQueue::SpdyWriteQueue() {}
+SpdyWriteQueue::SpdyWriteQueue() : removing_writes_(false) {}
SpdyWriteQueue::~SpdyWriteQueue() {
Clear();
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())
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();
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);
}
#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];
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;
}
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