mirror of
https://github.com/pocoproject/poco.git
synced 2025-10-14 23:07:56 +02:00
Feature net udp (#2347)
* add PMTU discovery #2329 * add socket gather/scatter capabilities #2330 (win, udp) * enable WSAPoll * add FastMemoryPool * add receiveFrom() with native args * allow copying of StringTokenizer * add AtomicFlag and SpinlockMutex * update .gitignore * UDPServer and client #2343 (windows) * fix warnings * fix warnings * regenerate Net VS solutions * regenerate CppUnit projects/solutions * clang fixes * gcc fixes * try to fix travis * more travis fixes * more travis fixes * handle UDPClient exception * fix makefiles and init order warnings * add UNIX gather/scatter sendto/recvfrom implementations and tests * run travis tests as sudo * try to run tests as sudo, 2nd attempt * fix warning * use mutex in reactor * lock-order-inversion in SocketReactor #2346 * add PMTU discovery #2329 (linux) * ICMPSocket does not check reply address #1921 * remove some ignored tests * add PMTU discovery #2329 (reconcile logic with #1921) * fix native receiveFrome() * reinstate ignoring of proxy errors * add testMTU to ignore list * add include atomic * NTPClient not checking reply address #2348 * some ICMP/MTU fixes * UDPSocketReader cleanup * resolve some socket inheritance warnings * add NTP time sync to ignored tests * SocketNotifier not thread-safe #2345 * prevent x64 samples build attempt for win32 * build TestApp and Library * fix ICMP tests * regen VS projects * regen VS projects and add missing 2012 files * remove debug prints
This commit is contained in:

committed by
GitHub

parent
da15142f69
commit
c4e676d36d
@@ -19,6 +19,7 @@
|
||||
|
||||
|
||||
#include "Poco/Foundation.h"
|
||||
#include "Poco/AtomicCounter.h"
|
||||
#include "Poco/Mutex.h"
|
||||
#include <vector>
|
||||
#include <cstddef>
|
||||
@@ -88,6 +89,298 @@ private:
|
||||
};
|
||||
|
||||
|
||||
//
|
||||
// FastMemoryPool
|
||||
//
|
||||
|
||||
// Macro defining the default initial size of any
|
||||
// FastMemoryPool; can be overriden by specifying
|
||||
// FastMemoryPool pre-alloc at runtime.
|
||||
#define POCO_FAST_MEMORY_POOL_PREALLOC 1000
|
||||
|
||||
|
||||
template <typename T, typename M = FastMutex>
|
||||
class FastMemoryPool
|
||||
/// FastMemoryPool is a class for pooling fixed-size blocks of memory.
|
||||
///
|
||||
/// The main purpose of this class is to speed-up memory allocations,
|
||||
/// as well as to reduce memory fragmentation in situations where the
|
||||
/// same blocks are allocated all over again, such as in server
|
||||
/// applications. It differs from the MemoryPool in the way the block
|
||||
/// size is determined - it is inferred form the held type size and
|
||||
/// applied statically. It is also, as its name implies, faster than
|
||||
/// Poco::MemoryPool. It is likely to be significantly faster than
|
||||
/// the runtime platform generic memory allocation functionality
|
||||
/// as well, but it has certain limitations (aside from only giving
|
||||
/// blocks of fixed size) - see more below.
|
||||
///
|
||||
/// An object using memory from the pool should be created using
|
||||
/// in-place new operator; once released back to the pool, its
|
||||
/// destructor will be called by the pool. The returned pointer
|
||||
/// must be a valid pointer to the type for which it was obtained.
|
||||
///
|
||||
/// Example use:
|
||||
///
|
||||
/// using std::vector;
|
||||
/// using std:string;
|
||||
/// using std::to_string;
|
||||
/// using Poco::FastMemoryPool;
|
||||
///
|
||||
/// int blocks = 10;
|
||||
/// FastMemoryPool<int> fastIntPool(blocks);
|
||||
/// FastMemoryPool<string> fastStringPool(blocks);
|
||||
///
|
||||
/// vector<int*> intVec(blocks, 0);
|
||||
/// vector<string*> strVec(blocks);
|
||||
///
|
||||
/// for (int i = 0; i < blocks; ++i)
|
||||
/// {
|
||||
/// intVec[i] = new (fastIntPool.get()) int(i);
|
||||
/// strVec[i] = new (fastStringPool.get()) string(to_string(i));
|
||||
/// }
|
||||
///
|
||||
/// for (int i = 0; i < blocks; ++i)
|
||||
/// {
|
||||
/// fastIntPool.release(intVec[i]);
|
||||
/// fastStringPool.release(strVec[i]);
|
||||
/// }
|
||||
///
|
||||
/// Pool keeps memory blocks in "buckets". A bucket is an array of
|
||||
/// blocks; it is always allocated with a single `new[]`, and its blocks
|
||||
/// are initialized at creation time. Whenever the current capacity
|
||||
/// of the pool is reached, a new bucket is allocated and its blocks
|
||||
/// initialized for internal use. If the new bucket allocation would
|
||||
/// exceed allowed maximum size, std::bad_alloc() exception is thrown,
|
||||
/// with object itself left intact.
|
||||
///
|
||||
/// Pool internally keeps track of available blocks through a linked-list
|
||||
/// and utilizes unused memory blocks for that purpose. This means that,
|
||||
/// for types smaller than pointer the size of a block will be greater
|
||||
/// than the size of the type. The implications are following:
|
||||
///
|
||||
/// - FastMemoryPool can not be used for arrays of types smaller
|
||||
/// than pointer
|
||||
///
|
||||
/// - if FastMemoryPool is used to store variable-size arrays, it
|
||||
/// must not have multiple buckets; the way to achieve this is by
|
||||
/// specifying proper argument values at construction.
|
||||
///
|
||||
/// Neither of the above are primarily intended or recommended modes
|
||||
/// of use. It is recommended to use a FastMemoryPool for creation of
|
||||
/// many objects of the same type. Furthermore, it is perfectly fine
|
||||
/// to have arrays or STL containers of pointers to objects created
|
||||
/// in blocks of memory obtained from the FastMemoryPool.
|
||||
///
|
||||
/// Before a block is given to the user, it is removed from the list;
|
||||
/// when a block is returned to the pool, it is re-inserted in the
|
||||
/// list. Pool will return held memory to the system at destruction,
|
||||
/// and will not leak memory after destruction; this means that after
|
||||
/// pool destruction, any memory that was taken, but not returned to
|
||||
/// it becomes invalid.
|
||||
///
|
||||
/// FastMemoryPool is thread safe; it uses Poco::FastMutex by
|
||||
/// default, but other mutexes can be specified through the template
|
||||
/// parameter, if needed. Poco::NullMutex can be specified as template
|
||||
/// parameter to avoid locking and improve speed in single-threaded
|
||||
/// scenarios.
|
||||
{
|
||||
private:
|
||||
class Block
|
||||
/// A block of memory. This class represents a memory
|
||||
/// block. It has dual use, the primary one being
|
||||
/// obvious - memory provided to the user of the pool.
|
||||
/// The secondary use is for internal "housekeeping"
|
||||
/// purposes.
|
||||
///
|
||||
/// It works like this:
|
||||
///
|
||||
/// - when initially created, a Block is properly
|
||||
/// constructed and positioned into the internal
|
||||
/// linked list of blocks
|
||||
///
|
||||
/// - when given to the user, the Block is removed
|
||||
/// from the internal linked list of blocks
|
||||
///
|
||||
/// - when returned back to the pool, the Block
|
||||
/// is again in-place constructed and inserted
|
||||
/// as next available block in the linked list
|
||||
/// of blocks
|
||||
{
|
||||
public:
|
||||
|
||||
Block()
|
||||
/// Creates a Block and sets its next pointer.
|
||||
/// This constructor should ony be used to initialize
|
||||
/// a block sequence (an array of blocks) in a newly
|
||||
/// allocated bucket.
|
||||
///
|
||||
/// After the construction, the last block's `next`
|
||||
/// pointer points outside the allocated memory and
|
||||
/// must be set to zero. This design improves performance,
|
||||
/// because otherwise the block array would require an
|
||||
/// initialization loop after the allocation.
|
||||
{
|
||||
_memory.next = this + 1;
|
||||
}
|
||||
|
||||
explicit Block(Block* next)
|
||||
/// Creates a Block and sets its next pointer.
|
||||
{
|
||||
_memory.next = next;
|
||||
}
|
||||
|
||||
union
|
||||
/// Memory block storage.
|
||||
///
|
||||
/// Note that this storage is properly aligned
|
||||
/// for the datatypes it holds. It will not work
|
||||
/// for arrays of types smaller than pointer size.
|
||||
/// Furthermore, the pool itself will not work for
|
||||
/// a variable-size array of any type after it is
|
||||
/// resized.
|
||||
{
|
||||
char buffer[sizeof(T)];
|
||||
Block* next;
|
||||
} _memory;
|
||||
|
||||
private:
|
||||
Block(const Block&);
|
||||
Block& operator = (const Block&);
|
||||
};
|
||||
|
||||
public:
|
||||
typedef M MutexType;
|
||||
typedef typename M::ScopedLock ScopedLock;
|
||||
|
||||
typedef Block* Bucket;
|
||||
typedef std::vector<Bucket> BucketVec;
|
||||
|
||||
FastMemoryPool(std::size_t blocksPerBucket = POCO_FAST_MEMORY_POOL_PREALLOC, std::size_t bucketPreAlloc = 10, std::size_t maxAlloc = 0):
|
||||
_blocksPerBucket(blocksPerBucket),
|
||||
_maxAlloc(maxAlloc),
|
||||
_available(0)
|
||||
/// Creates the FastMemoryPool.
|
||||
///
|
||||
/// The size of a block is inferred from the type size. Number of blocks
|
||||
/// per bucket, pre-allocated bucket pointer storage and maximum allowed
|
||||
/// total size of the pool can be customized by overriding default
|
||||
/// parameter value:
|
||||
///
|
||||
/// - blocksPerBucket specifies how many blocks each bucket contains
|
||||
/// defaults to POCO_FAST_MEMORY_POOL_PREALLOC
|
||||
///
|
||||
/// - bucketPreAlloc specifies how much space for bucket pointers
|
||||
/// (buckets themselves are not pre-allocated) will
|
||||
/// be pre-alocated.
|
||||
///
|
||||
/// - maxAlloc specifies maximum allowed total pool size in bytes.
|
||||
{
|
||||
if (_blocksPerBucket < 2)
|
||||
throw std::invalid_argument("FastMemoryPool: blocksPerBucket must be >=2");
|
||||
_buckets.reserve(bucketPreAlloc);
|
||||
resize();
|
||||
}
|
||||
|
||||
~FastMemoryPool()
|
||||
/// Destroys the FastMemoryPool and releases all memory.
|
||||
/// Any memory taken from, but not returned to, the pool
|
||||
/// becomes invalid.
|
||||
{
|
||||
clear();
|
||||
}
|
||||
|
||||
void* get()
|
||||
/// Returns pointer to the next available
|
||||
/// memory block. If the pool is exhausted,
|
||||
/// it will be resized by allocating a new
|
||||
/// bucket.
|
||||
{
|
||||
Block* ret;
|
||||
{
|
||||
ScopedLock l(_mutex);
|
||||
if(_firstBlock == 0) resize();
|
||||
ret = _firstBlock;
|
||||
_firstBlock = _firstBlock->_memory.next;
|
||||
}
|
||||
--_available;
|
||||
return ret;
|
||||
}
|
||||
|
||||
template <typename P>
|
||||
void release(P* ptr)
|
||||
/// Recycles the released memory by initializing it for
|
||||
/// internal use and setting it as next available block;
|
||||
/// previously next block becomes this block's next.
|
||||
/// Releasing of null pointers is silently ignored.
|
||||
/// Destructor is called for the returned pointer.
|
||||
{
|
||||
if (!ptr) return;
|
||||
reinterpret_cast<P*>(ptr)->~P();
|
||||
++_available;
|
||||
ScopedLock l(_mutex);
|
||||
_firstBlock = new (ptr) Block(_firstBlock);
|
||||
}
|
||||
|
||||
std::size_t blockSize() const
|
||||
/// Returns the block size in bytes.
|
||||
{
|
||||
return sizeof(Block);
|
||||
}
|
||||
|
||||
std::size_t allocated() const
|
||||
/// Returns the total amount of memory allocated, in bytes.
|
||||
{
|
||||
return _buckets.size() * _blocksPerBucket;
|
||||
}
|
||||
|
||||
std::size_t available() const
|
||||
/// Returns currently available amount of memory in bytes.
|
||||
{
|
||||
return _available;
|
||||
}
|
||||
|
||||
private:
|
||||
FastMemoryPool(const FastMemoryPool&);
|
||||
FastMemoryPool& operator = (const FastMemoryPool&);
|
||||
|
||||
void resize()
|
||||
/// Creates new bucket and initializes it for internal use.
|
||||
/// Sets the previously next block to point to the new bucket's
|
||||
/// first block and the new bucket's last block becomes the
|
||||
/// last block.
|
||||
{
|
||||
if (_buckets.size() == _buckets.capacity())
|
||||
{
|
||||
std::size_t newSize = _buckets.capacity() * 2;
|
||||
if (_maxAlloc != 0 && newSize > _maxAlloc) throw std::bad_alloc();
|
||||
_buckets.reserve(newSize);
|
||||
}
|
||||
_buckets.push_back(new Block[_blocksPerBucket]);
|
||||
_firstBlock = _buckets.back();
|
||||
// terminate last block
|
||||
_firstBlock[_blocksPerBucket-1]._memory.next = 0;
|
||||
_available = _available.value() + static_cast<AtomicCounter::ValueType>(_blocksPerBucket);
|
||||
}
|
||||
|
||||
void clear()
|
||||
{
|
||||
typename BucketVec::iterator it = _buckets.begin();
|
||||
typename BucketVec::iterator end = _buckets.end();
|
||||
for (; it != end; ++it) delete[] *it;
|
||||
}
|
||||
|
||||
typedef Poco::AtomicCounter Counter;
|
||||
|
||||
const
|
||||
std::size_t _blocksPerBucket;
|
||||
BucketVec _buckets;
|
||||
Block* _firstBlock;
|
||||
std::size_t _maxAlloc;
|
||||
Counter _available;
|
||||
mutable M _mutex;
|
||||
};
|
||||
|
||||
|
||||
//
|
||||
// inlines
|
||||
//
|
||||
|
Reference in New Issue
Block a user