summaryrefslogtreecommitdiffstats
path: root/net/quic/blocked_list.h
blob: 3a7f989eeec6ccbb75139ce305cf4312395707ee (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// A combined list/hash set for read or write-blocked entities.

#ifndef NET_QUIC_BLOCKED_LIST_H_
#define NET_QUIC_BLOCKED_LIST_H_

#include <list>

#include "base/containers/hash_tables.h"
#include "base/logging.h"

namespace net {

template <typename Object>
class BlockedList {
 public:
  // Called to add an object to the blocked list. This indicates
  // the object should be notified when it can use the socket again.
  //
  // If this object is already on the list, it will not be added again.
  void AddBlockedObject(Object object) {
    // Only add the object to the list if we successfully add it to the set.
    if (object_set_.insert(object).second) {
      object_list_.push_back(object);
    }
  }

  // Called to remove an object from a blocked list.  This should be
  // called in the event the object is being deleted before the list is.
  void RemoveBlockedObject(Object object) {
    // Remove the object from the set.  We'll check the set before calling
    // OnCanWrite on a object from the list.
    //
    // There is potentially ordering unfairness should a session be removed and
    // then readded (as it keeps its position in the list) but it's not worth
    // the overhead to walk the list and remove it.
    object_set_.erase(object);
  }

  // Called when the socket is usable and some objects can access it.  Returns
  // the first object and removes it from the list.
  Object GetNextBlockedObject() {
    DCHECK(!IsEmpty());

    // Walk the list to find the first object which was not removed from the
    // set.
    while (!object_list_.empty()) {
      Object object = *object_list_.begin();
      object_list_.pop_front();
      int removed = object_set_.erase(object);
      if (removed > 0) {
        return object;
      }
    }

    // This is a bit of a hack: It's illegal to call GetNextBlockedObject() if
    // the list is empty (see DCHECK above) but we must return something.  This
    // compiles for ints (returns 0) and pointers in the case that someone has a
    // bug in their call site.
    return 0;
  };

  // Returns the number of objects in the blocked list.
  int NumObjects() {
    return object_set_.size();
  };

  // Returns true if there are no objects in the list, false otherwise.
  bool IsEmpty() {
    return object_set_.empty();
  };

 private:
  // A set tracking the objects. This is the authoritative container for
  // determining if an object is blocked.   Objects in the list will always
  // be in the set.
  base::hash_set<Object> object_set_;
  // A list tracking the order in which objects were added to the list.
  // Objects are added to the back and pulled off the front, but only get
  // resumption calls if they're still in the set.
  // It's possible to be in the list twice, but only the first entry will get an
  // OnCanWrite call.
  std::list<Object> object_list_;
};

}  // namespace net

#endif  // NET_QUIC_BLOCKED_LIST_H_