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:
Aleksandar Fabijanic
2018-06-02 14:02:33 -05:00
committed by GitHub
parent da15142f69
commit c4e676d36d
127 changed files with 5540 additions and 1408 deletions

View File

@@ -0,0 +1,125 @@
//
// AtomicFlag.h
//
// Library: Foundation
// Package: Core
// Module: AtomicFlag
//
// Definition of the AtomicFlag class.
//
// Copyright (c) 2009, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#ifdef POCO_HAVE_STD_ATOMICS
#ifndef Foundation_AtomicFlag_INCLUDED
#define Foundation_AtomicFlag_INCLUDED
#include "Poco/Foundation.h"
#include <atomic>
namespace Poco {
class Foundation_API AtomicFlag
/// This class implements an atomic boolean flag by wrapping
/// the std::atomic_flag. It is guaranteed to be thread-safe
/// and lock-free.
///
/// Only default-construction is allowed, objects of this
/// class are not copyable, assignable or movable.
///
/// Note that this class is not a replacement for (atomic)
/// bool type because its value can not be read without also
/// being set to true. However, after being set (either
/// explicitly, through the set() call or implicitly, via
/// operator bool()), it can be reset and reused.
///
/// The class is useful in scenarios such as busy-wait or
/// one-off code blocks, e.g.:
///
/// class MyClass
/// {
/// public:
/// void myFunc()
/// {
/// if (!_beenHere) doOnce();
/// doMany();
/// }
///
/// void doOnce() { /* executed once */ }
///
/// void doMany() { /* executed multiple times */ }
///
/// private:
/// AtomicFlag _beenHere;
/// }
///
/// MyClass myClass;
/// int i = 0;
/// while (++i < 10) myClass.myFunc();
{
public:
AtomicFlag();
/// Creates AtomicFlag.
~AtomicFlag();
/// Destroys AtomicFlag.
bool set();
/// Sets the flag to true and returns previously
/// held value.
void reset();
/// Resets the flag to false.
operator bool ();
/// Sets the flag to true and returns previously
/// held value.
private:
AtomicFlag(const AtomicFlag&) = delete;
AtomicFlag& operator = (const AtomicFlag&) = delete;
AtomicFlag(AtomicFlag&&) = delete;
AtomicFlag& operator = (AtomicFlag&&) = delete;
std::atomic_flag _flag = ATOMIC_FLAG_INIT;
};
//
// inlines
//
inline bool AtomicFlag::set()
{
return _flag.test_and_set(std::memory_order_acquire);
}
inline void AtomicFlag::reset()
{
_flag.clear(std::memory_order_release);
}
inline AtomicFlag::operator bool ()
{
return set();
}
} // namespace Poco
#endif // Foundation_AtomicFlag_INCLUDED
#endif // POCO_HAVE_STD_ATOMICS

View File

@@ -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
//

View File

@@ -21,6 +21,17 @@
#include "Poco/Foundation.h"
#include "Poco/Exception.h"
#include "Poco/ScopedLock.h"
#include "Poco/Timestamp.h"
#if __cplusplus >= 201103L
#ifndef POCO_HAVE_STD_ATOMICS
#define POCO_HAVE_STD_ATOMICS
#endif
#endif
#ifdef POCO_HAVE_STD_ATOMICS
#include <atomic>
#endif
#if defined(POCO_OS_FAMILY_WINDOWS)
@@ -150,6 +161,58 @@ private:
};
#ifdef POCO_HAVE_STD_ATOMICS
class Foundation_API SpinlockMutex
/// A SpinlockMutex, implemented in terms of std::atomic_flag, as
/// busy-wait mutual exclusion.
///
/// While in some cases (eg. locking small blocks of code)
/// busy-waiting may be an optimal solution, in many scenarios
/// spinlock may not be the right choice - it is up to the user to
/// choose the proper mutex type for their particular case.
///
/// Works with the ScopedLock class.
{
public:
typedef Poco::ScopedLock<SpinlockMutex> ScopedLock;
SpinlockMutex();
/// Creates the SpinlockMutex.
~SpinlockMutex();
/// Destroys the SpinlockMutex.
void lock();
/// Locks the mutex. Blocks if the mutex
/// is held by another thread.
void lock(long milliseconds);
/// Locks the mutex. Blocks up to the given number of milliseconds
/// if the mutex is held by another thread. Throws a TimeoutException
/// if the mutex can not be locked within the given timeout.
bool tryLock();
/// Tries to lock the mutex. Returns immediately, false
/// if the mutex is already held by another thread, true
/// if the mutex was successfully locked.
bool tryLock(long milliseconds);
/// Locks the mutex. Blocks up to the given number of milliseconds
/// if the mutex is held by another thread.
/// Returns true if the mutex was successfully locked.
void unlock();
/// Unlocks the mutex so that it can be acquired by
/// other threads.
private:
std::atomic_flag _flag = ATOMIC_FLAG_INIT;
};
#endif // POCO_HAVE_STD_ATOMICS
class Foundation_API NullMutex
/// A NullMutex is an empty mutex implementation
/// which performs no locking at all. Useful in policy driven design
@@ -202,6 +265,11 @@ public:
//
// inlines
//
//
// Mutex
//
inline void Mutex::lock()
{
lockImpl();
@@ -233,6 +301,10 @@ inline void Mutex::unlock()
}
//
// FastMutex
//
inline void FastMutex::lock()
{
lockImpl();
@@ -264,6 +336,55 @@ inline void FastMutex::unlock()
}
#ifdef POCO_HAVE_STD_ATOMICS
//
// SpinlockMutex
//
inline void SpinlockMutex::lock()
{
while (_flag.test_and_set(std::memory_order_acquire));
}
inline void SpinlockMutex::lock(long milliseconds)
{
Timestamp now;
Timestamp::TimeDiff diff(Timestamp::TimeDiff(milliseconds)*1000);
while (_flag.test_and_set(std::memory_order_acquire))
{
if (now.isElapsed(diff)) throw TimeoutException();
}
}
inline bool SpinlockMutex::tryLock()
{
return !_flag.test_and_set(std::memory_order_acquire);
}
inline bool SpinlockMutex::tryLock(long milliseconds)
{
Timestamp now;
Timestamp::TimeDiff diff(Timestamp::TimeDiff(milliseconds)*1000);
while (_flag.test_and_set(std::memory_order_acquire))
{
if (now.isElapsed(diff)) return false;
}
return true;
}
inline void SpinlockMutex::unlock()
{
_flag.clear(std::memory_order_release);
}
#endif // POCO_HAVE_STD_ATOMICS
} // namespace Poco

View File

@@ -36,7 +36,7 @@ public:
enum Options
{
TOK_IGNORE_EMPTY = 1, /// ignore empty tokens
TOK_TRIM = 2 /// remove leading and trailing whitespace from tokens
TOK_TRIM = 2 /// remove leading and trailing whitespace from tokens
};
typedef std::vector<std::string> TokenVec;
@@ -83,9 +83,6 @@ public:
/// Returns the number of tokens equal to the specified token.
private:
StringTokenizer(const StringTokenizer&);
StringTokenizer& operator = (const StringTokenizer&);
void trim(std::string& token);
TokenVec _tokens;