1 // Copyright 2018 The Chromium Authors 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #ifndef NET_BASE_DATAGRAM_BUFFER_H_ 6 #define NET_BASE_DATAGRAM_BUFFER_H_ 7 8 #include <list> 9 10 #include "base/memory/weak_ptr.h" 11 #include "net/base/net_export.h" 12 13 namespace net { 14 15 // An IO buffer, (at least initially) specifically for use with the 16 // new DatagramClientSocket::WriteAsync method, with the following key 17 // features: 18 // 19 // 1) Meant to be easily batched when that improves efficiency. The 20 // primary goal of WriteAsync is to enable enlisting an 21 // additional cpu core for the kernel part of socket write. 22 // 2) Uses unique_ptr (with std::move) rather than reference 23 // counting as in IOBuffers. The benefit is safer cancellation 24 // semantics, IOBuffer used reference count to enforce unique 25 // ownership in an idiomatic fashion. unique_ptr is ligher weight 26 // as it doesn't use thread safe primitives as 27 // RefCountedThreadSafe does. 28 // 3) Provides a pooling allocator, which for datagram buffers is 29 // much cheaper than using fully general allocator (e.g. malloc 30 // etc.). The implementation takes advantage of 31 // std::list::splice so that costs associated with allocations 32 // and copies of pool metadata quickly amortize to zero, and all 33 // common operations are O(1). 34 35 class DatagramBuffer; 36 37 // Batches of DatagramBuffers are treated as a FIFO queue, implemented 38 // by |std::list|. Note that |std::list::splice()| is attractive for 39 // this use case because it keeps most operations to O(1) and 40 // minimizes allocations/frees and copies. 41 typedef std::list<std::unique_ptr<DatagramBuffer>> DatagramBuffers; 42 43 class NET_EXPORT_PRIVATE DatagramBufferPool { 44 public: 45 // |max_buffer_size| must be >= largest |buf_len| provided to 46 // ||New()|. 47 explicit DatagramBufferPool(size_t max_buffer_size); 48 DatagramBufferPool(const DatagramBufferPool&) = delete; 49 DatagramBufferPool& operator=(const DatagramBufferPool&) = delete; 50 virtual ~DatagramBufferPool(); 51 // Insert a new element (drawn from the pool) containing a copy of 52 // |buffer| to |buffers|. Caller retains owenership of |buffers| and |buffer|. 53 void Enqueue(const char* buffer, size_t buf_len, DatagramBuffers* buffers); 54 // Return all elements of |buffers| to the pool. Caller retains 55 // ownership of |buffers|. 56 void Dequeue(DatagramBuffers* buffers); 57 max_buffer_size()58 size_t max_buffer_size() { return max_buffer_size_; } 59 60 private: 61 const size_t max_buffer_size_; 62 DatagramBuffers free_list_; 63 }; 64 65 // |DatagramBuffer|s can only be created via 66 // |DatagramBufferPool::Enqueue()|. 67 // 68 69 // |DatagramBuffer|s should be recycled via 70 // |DatagramBufferPool::Dequeue|. Care must be taken when a 71 // |DatagramBuffer| is moved to another thread via 72 // |PostTask|. |Dequeue| is not expected to be thread-safe, so it 73 // is preferred to move the |DatagramBuffer|s back to the thread where 74 // the pool lives (e.g. using |PostTaskAndReturnWithResult|) and 75 // dequeuing them from there. In the exception of pathalogical 76 // cancellation (e.g. due to thread tear-down), the destructor will 77 // release its memory permanently rather than returning to the pool. 78 class NET_EXPORT_PRIVATE DatagramBuffer { 79 public: 80 DatagramBuffer() = delete; 81 DatagramBuffer(const DatagramBuffer&) = delete; 82 DatagramBuffer& operator=(const DatagramBuffer&) = delete; 83 ~DatagramBuffer(); 84 85 char* data() const; 86 size_t length() const; 87 88 protected: 89 explicit DatagramBuffer(size_t max_packet_size); 90 91 private: 92 friend class DatagramBufferPool; 93 94 void Set(const char* buffer, size_t buf_len); 95 96 std::unique_ptr<char[]> data_; 97 size_t length_ = 0; 98 }; 99 100 } // namespace net 101 102 #endif // NET_BASE_DATAGRAM_BUFFER_H_ 103