This commit is contained in:
2025-11-24 14:19:51 +05:30
commit f5c1412b28
6734 changed files with 1527575 additions and 0 deletions

View File

@ -0,0 +1,435 @@
/*
Copyright (c) 2009-2010 Christopher A. Taylor. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of LibCat nor the names of its contributors may be used
to endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
/*
* Modified work: Copyright (c) 2017, SLikeSoft UG (haftungsbeschr<68>nkt)
*
* This source code was modified by SLikeSoft. Modifications are licensed under the MIT-style
* license found in the license.txt file in the root directory of this source tree.
* Alternatively you are permitted to license the modifications under the Modified BSD License.
*/
#ifndef CAT_ATOMIC_HPP
#define CAT_ATOMIC_HPP
#include <cat/Platform.hpp>
#if defined(CAT_OS_WINDOWS)
# include <cat/port/WindowsInclude.hpp>
#endif
namespace cat {
namespace Atomic {
// Compare-and-Swap 2x word size (CAS2)
// On 32-bit architectures, the arguments point to 64-bit values, and must be aligned to 8 byte boundary
// On 64-bit architectures, the arguments point to 128-bit values, and must be aligned to 16 byte boundary
// Returns true if the old value was equal to the expected value
CAT_INLINE bool CAS2(volatile void *x, const void *expected_old_value, const void *new_value);
// Will define CAT_NO_ATOMIC_CAS2 if the platform/compiler does not support atomic CAS2
// Add y to x, returning the previous state of x
CAT_INLINE u32 Add(volatile u32 *x, s32 y);
// Will define CAT_NO_ATOMIC_ADD if the platform/compiler does not support atomic add
// Set x to new value, returning the previous state of x
CAT_INLINE u32 Set(volatile u32 *x, u32 new_value);
// Will define CAT_NO_ATOMIC_SET if the platform/compiler does not support atomic set
// Bit Test and Set (BTS)
// Returns true if the bit was 1 and is still 1, otherwise false
CAT_INLINE bool BTS(volatile u32 *x, int bit);
// Will define CAT_NO_ATOMIC_BTS if the platform/compiler does not support atomic bts
// Bit Test and Reset (BTR)
// Returns true if the bit was 1 and is now 0, otherwise false
CAT_INLINE bool BTR(volatile u32 *x, int bit);
// Will define CAT_NO_ATOMIC_BTR if the platform/compiler does not support atomic btr
} // namespace Atomic
//// Compare-and-Swap
#if defined(CAT_WORD_64)
bool Atomic::CAS2(volatile void *x, const void *expected_old_value, const void *new_value)
{
CAT_FENCE_COMPILER
#if defined(CAT_COMPILER_MSVC) && (_MSC_VER > 1400) // MSVC 2008+
__int64 ComparandResult[2] = { ((u64*)expected_old_value)[0],
((u64*)expected_old_value)[1] };
// Requires MSVC 2008 or newer
bool success = 1 == _InterlockedCompareExchange128((s64*)x, ((u64*)new_value)[1],
((u64*)new_value)[0], ComparandResult);
CAT_FENCE_COMPILER
return success;
#elif defined(CAT_ASM_ATT) && defined(CAT_ISA_X86)
u128 *target = (u128*)x;
u64 *replace = (u64*)new_value;
u128 *expected = (u128*)expected_old_value;
bool retval;
CAT_ASM_BEGIN
"lock; CMPXCHG16B %0\n\t"
"sete %%al"
: "=m" (*target), "=a" (retval)
: "m" (*target), "b" (replace[0]), "c" (replace[1]), "A" (*expected)
: "memory", "cc"
CAT_ASM_END
CAT_FENCE_COMPILER
return retval;
#else
#define CAT_NO_ATOMIC_CAS2 /* Platform/compiler does not support CAS2 */
(void) x; // avoid unused parameter warning
(void) expected_old_value;
(void) new_value;
return true;
#endif
}
#else // 32-bit version:
bool Atomic::CAS2(volatile void *x, const void *expected_old_value, const void *new_value)
{
CAT_FENCE_COMPILER
#if defined(CAT_COMPILER_MSVC)
s64 old_value = ((s64*)expected_old_value)[0];
bool success = (old_value == _InterlockedCompareExchange64((s64*)x, ((s64*)new_value)[0], old_value));
CAT_FENCE_COMPILER
return success;
#elif defined(CAT_ASM_INTEL) && defined(CAT_ISA_X86)
CAT_ASM_BEGIN
push ebx
mov eax, new_value
push esi
mov ebx, dword ptr[eax]
mov ecx, dword ptr[eax+4]
mov edx, expected_old_value
mov esi, x
mov eax, dword ptr[edx]
mov edx, dword ptr[edx+4]
lock CMPXCHG8B qword ptr[esi]
pop ebx
mov eax, 0
pop esi
setz al
CAT_ASM_END
CAT_FENCE_COMPILER
#elif defined(CAT_ASM_ATT) && defined(CAT_ISA_X86)
u64 *target = (u64*)x;
u32 *replace = (u32*)new_value;
u64 *expected = (u64*)expected_old_value;
bool retval;
CAT_ASM_BEGIN
"lock; CMPXCHG8B %0\n\t"
"sete %%al"
: "=m" (*target), "=a" (retval)
: "m" (*target), "b" (replace[0]), "c" (replace[1]), "A" (*expected)
: "memory", "cc"
CAT_ASM_END
CAT_FENCE_COMPILER
return retval;
#else
#define CAT_NO_ATOMIC_CAS2 /* Platform/compiler does not support atomic CAS2 */
(void) x; // avoid unused parameter warning
(void) expected_old_value;
(void) new_value;
return true;
#endif
}
#endif // defined(CAT_WORD_64)
//// Add y to x, returning the previous state of x
u32 Atomic::Add(volatile u32 *x, s32 y)
{
CAT_FENCE_COMPILER
#if defined(CAT_COMPILER_MSVC) && defined(CAT_WORD_64)
u32 result = InterlockedAdd((volatile LONG*)x, y) - y;
CAT_FENCE_COMPILER
return result;
#elif defined(CAT_ASM_INTEL) && defined(CAT_WORD_32) && defined(CAT_ISA_X86)
CAT_ASM_BEGIN
mov edx,x
mov eax,y
lock XADD [edx],eax
CAT_ASM_END
CAT_FENCE_COMPILER
#elif defined(CAT_ASM_ATT) && defined(CAT_ISA_X86)
u32 retval;
CAT_ASM_BEGIN
"lock; XADDl %%eax, %0\n\t"
: "=m" (*x), "=a" (retval)
: "m" (*x), "a" (y)
: "memory", "cc"
CAT_ASM_END
CAT_FENCE_COMPILER
return retval;
#else
#define CAT_NO_ATOMIC_ADD /* Platform/compiler does not support atomic add */
u32 old_x = *x;
*x = old_x + y;
CAT_FENCE_COMPILER
return old_x;
#endif
}
//// Set x to new value, returning the previous state of x
u32 Atomic::Set(volatile u32 *x, u32 new_value)
{
CAT_FENCE_COMPILER
#if defined(CAT_COMPILER_MSVC)
#if (_MSC_VER <= 1400) // MSVC 2005
u32 result = _InterlockedExchange((long*)x, new_value);
#else // MSVC 2008+
u32 result = _InterlockedExchange((volatile LONG*)x, new_value);
#endif
CAT_FENCE_COMPILER
return result;
#elif defined(CAT_ASM_INTEL) && defined(CAT_WORD_32) && defined(CAT_ISA_X86)
CAT_ASM_BEGIN
mov edx,x
mov eax,new_value
lock XCHG [edx],eax
CAT_ASM_END
CAT_FENCE_COMPILER
#elif defined(CAT_ASM_ATT) && defined(CAT_ISA_X86)
u32 retval;
CAT_ASM_BEGIN
"lock; XCHGl %%eax, %0\n\t"
: "=m" (*x), "=a" (retval)
: "m" (*x), "a" (new_value)
: "memory", "cc"
CAT_ASM_END
CAT_FENCE_COMPILER
return retval;
#else
#define CAT_NO_ATOMIC_SET /* Platform/compiler does not support atomic set */
u32 old_x = *x;
*x = new_value;
CAT_FENCE_COMPILER
return old_x;
#endif
}
//// Bit Test and Set (BTS)
bool Atomic::BTS(volatile u32 *x, int bit)
{
CAT_FENCE_COMPILER
#if defined(CAT_COMPILER_MSVC)
#if (_MSC_VER <= 1400) // MSVC 2005
bool success = !!_interlockedbittestandset((long*)x, bit);
#else // MSVC 2008+
bool success = !!_interlockedbittestandset((volatile LONG*)x, bit);
#endif
CAT_FENCE_COMPILER
return success;
#elif defined(CAT_ASM_INTEL) && defined(CAT_WORD_32) && defined(CAT_ISA_X86)
CAT_ASM_BEGIN
mov edx,x
mov ecx,bit
lock BTS [edx],ecx
mov eax,0
setc al
CAT_ASM_END
CAT_FENCE_COMPILER
#elif defined(CAT_ASM_ATT) && defined(CAT_ISA_X86)
bool retval;
CAT_ASM_BEGIN
"lock; BTSl %2, %0\n\t"
"setc %%al"
: "=m" (*x), "=a" (retval)
: "Ir" (bit)
: "memory", "cc"
CAT_ASM_END
CAT_FENCE_COMPILER
return retval;
#else
#define CAT_NO_ATOMIC_BTS /* Platform/compiler does not support atomic bts */
u32 mask = 1 << bit;
u32 old_x = *x;
*x = old_x | mask;
CAT_FENCE_COMPILER
return (old_x & mask) ? true : false;
#endif
}
//// Bit Test and Reset (BTR)
bool Atomic::BTR(volatile u32 *x, int bit)
{
CAT_FENCE_COMPILER
#if defined(CAT_COMPILER_MSVC)
#if (_MSC_VER <= 1400) // MSVC 2005
bool success = !!_interlockedbittestandreset((long*)x, bit);
#else // MSVC 2008+
bool success = !!_interlockedbittestandreset((volatile LONG*)x, bit);
#endif
CAT_FENCE_COMPILER
return success;
#elif defined(CAT_ASM_INTEL) && defined(CAT_WORD_32) && defined(CAT_ISA_X86)
CAT_ASM_BEGIN
mov edx,x
mov ecx,bit
lock BTR [edx],ecx
mov eax,0
setc al
CAT_ASM_END
CAT_FENCE_COMPILER
#elif defined(CAT_ASM_ATT) && defined(CAT_ISA_X86)
bool retval;
CAT_ASM_BEGIN
"lock; BTRl %2, %0\n\t"
"setc %%al"
: "=m" (*x), "=a" (retval)
: "Ir" (bit)
: "memory", "cc"
CAT_ASM_END
CAT_FENCE_COMPILER
return retval;
#else
#define CAT_NO_ATOMIC_BTR /* Platform/compiler does not support atomic btr */
u32 mask = 1 << bit;
u32 old_x = *x;
*x = old_x & ~mask;
CAT_FENCE_COMPILER
return (old_x & mask) ? true : false;
#endif
}
} // namespace cat
#endif // CAT_ATOMIC_HPP

View File

@ -0,0 +1,368 @@
/*
Copyright (c) 2009-2010 Christopher A. Taylor. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of LibCat nor the names of its contributors may be used
to endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
/*
Algorithm from "An Optimistic Approach to Lock-Free FIFO Queues"
Edya Ladan-Mozes and Nir Shavit (2004)
*/
#ifndef CAT_LOCKLESS_FIFO_HPP
#define CAT_LOCKLESS_FIFO_HPP
#include <cat/threads/RegionAllocator.hpp>
#include <cat/threads/Atomic.hpp>
#if defined(CAT_OS_WINDOWS)
# include <cat/port/WindowsInclude.hpp>
#else
# error "Not portable to your OS!"
#endif
namespace cat {
namespace FIFO {
template<class T> class Ptr;
template<class T> class Node;
template<class T> class Queue;
//// Ptr
// Union for an ABA-proof pointer
template<class T>
class Ptr
{
public:
union
{
struct
{
Node<T> *ptr;
#if defined(CAT_WORD_64)
u64 tag;
#else
u32 tag;
#endif
};
#if defined(CAT_WORD_64)
volatile u64 N[2];
#else
volatile u64 N;
#endif
} CAT_PACKED;
Ptr(); // zero everything
bool operator==(const Ptr<T> &rhs);
bool operator!=(const Ptr<T> &rhs);
};
//// Derive from Data<T> for data passed through the queue
template<class T>
class Node
{
friend class Queue<T>;
T *value;
Ptr<T> next, prev;
};
//// Queue
// Performs lazy deallocation of data objects on behalf of the caller,
// freeing all remaining objects when the Queue goes out of scope.
template<class T>
class Queue
{
// Pointer to head and tail
Ptr<T> Head, Tail;
// Event to wait on if dequeuing
#if defined(CAT_OS_WINDOWS)
HANDLE hEvent;
#endif
public:
Queue();
~Queue();
public:
void Enqueue(T *data);
T *Dequeue();
void FixList(Ptr<T> tail, Ptr<T> head);
// Enqueue a new event to wake up a thread stuck here
T *DequeueWait();
};
//// Compare-and-Swap x2 (CAS2) atomic operation
template<class T>
inline bool CAS2(Ptr<T> &destination, const Ptr<T> &expected, const Ptr<T> &replacement)
{
return Atomic::CAS2(&destination, &expected, &replacement);
}
//// Ptr: Templated member implementation
template<class T>
Ptr<T>::Ptr()
{
#if defined(CAT_WORD_64)
N[0] = 0;
N[1] = 0;
#else
N = 0;
#endif
}
template<class T>
bool Ptr<T>::operator==(const Ptr<T> &n)
{
#if defined(CAT_WORD_64)
return N[0] == n.N[0] && N[1] == n.N[1];
#else
return N == n.N;
#endif
}
template<class T>
bool Ptr<T>::operator!=(const Ptr<T> &n)
{
#if defined(CAT_WORD_64)
return N[0] != n.N[0] || N[1] != n.N[1];
#else
return N != n.N;
#endif
}
//// Queue: Templated member implementation
template<class T>
Queue<T>::Queue()
{
#if defined(CAT_OS_WINDOWS)
hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
#endif
Node<T> *node = new (RegionAllocator::ii) Node<T>;
node->value = 0;
Head.ptr = Tail.ptr = node;
}
template<class T>
Queue<T>::~Queue()
{
// Destroy objects that are still queued
for (Node<T> *next, *ptr = Head.ptr; ptr; ptr = next)
{
next = ptr->next.ptr;
if (ptr->value)
RegionAllocator::ii->Delete(ptr->value);
RegionAllocator::ii->Delete(ptr);
}
#if defined(CAT_OS_WINDOWS)
CloseHandle(hEvent);
#endif
}
template<class T>
void Queue<T>::Enqueue(T *val)
{
Ptr<T> tail;
Node<T> *nd = new (RegionAllocator::ii) Node<T>;
nd->value = val;
for (;;)
{
tail = Tail;
nd->next.ptr = tail.ptr;
nd->next.tag = tail.tag + 1;
Ptr<T> new_tail;
new_tail.ptr = nd;
new_tail.tag = tail.tag + 1;
if (CAS2(Tail, tail, new_tail))
{
tail.ptr->prev.ptr = nd;
tail.ptr->prev.tag = tail.tag;
break;
}
}
#if defined(CAT_OS_WINDOWS)
SetEvent(hEvent);
#endif
}
template<class T>
T *Queue<T>::DequeueWait()
{
for (;;)
{
// Attempt to dequeue a message
// If we won the race to service the message, then return it
T *retval = Dequeue();
if (retval) return retval;
#if defined(CAT_OS_WINDOWS)
// If the sychronization wait fails (handle closed), abort with 0
if (WaitForSingleObject(hEvent, INFINITE) != WAIT_OBJECT_0)
return 0;
#endif
}
}
template<class T>
T *Queue<T>::Dequeue()
{
Ptr<T> tail, head, firstNodePrev;
Node<T> *nd_dummy;
T *val;
for (;;)
{
head = Head;
tail = Tail;
firstNodePrev = head.ptr->prev;
val = head.ptr->value;
if (head == Head)
{
if (val != 0)
{
if (tail != head)
{
if (firstNodePrev.tag != head.tag)
{
FixList(tail, head);
continue;
}
}
else
{
nd_dummy = new (RegionAllocator::ii) Node<T>;
nd_dummy->value = 0;
nd_dummy->next.ptr = tail.ptr;
nd_dummy->next.tag = tail.tag + 1;
Ptr<T> new_tail;
new_tail.ptr = nd_dummy;
new_tail.tag = tail.tag + 1;
if (CAS2(Tail, tail, new_tail))
{
head.ptr->prev.ptr = nd_dummy;
head.ptr->prev.tag = tail.tag;
}
else
{
RegionAllocator::ii->Delete(nd_dummy);
}
continue;
}
Ptr<T> new_head;
new_head.ptr = firstNodePrev.ptr;
new_head.tag = head.tag + 1;
if (CAS2(Head, head, new_head))
{
RegionAllocator::ii->Delete(head.ptr);
return val;
}
}
else
{
if (tail.ptr == head.ptr)
return 0;
if (firstNodePrev.tag != head.tag)
{
FixList(tail, head);
continue;
}
Ptr<T> new_head;
new_head.ptr = firstNodePrev.ptr;
new_head.tag = head.tag + 1;
CAS2(Head, head, new_head);
}
}
}
}
template<class T>
void Queue<T>::FixList(Ptr<T> tail, Ptr<T> head)
{
Ptr<T> curNode, curNodeNext, nextNodePrev;
curNode = tail;
while (head == Head && curNode != head)
{
curNodeNext = curNode.ptr->next;
if (curNodeNext.tag != curNode.tag)
return;
nextNodePrev = curNodeNext.ptr->prev;
if (nextNodePrev.ptr != curNode.ptr || nextNodePrev.tag != curNode.tag - 1)
{
curNodeNext.ptr->prev.ptr = curNode.ptr;
curNodeNext.ptr->prev.tag = curNode.tag - 1;
}
curNode.ptr = curNodeNext.ptr;
curNode.tag = curNode.tag - 1;
}
}
} // namespace FIFO
} // namespace cat
#endif // CAT_LOCKLESS_FIFO_HPP

View File

@ -0,0 +1,78 @@
/*
Copyright (c) 2009-2010 Christopher A. Taylor. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of LibCat nor the names of its contributors may be used
to endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef CAT_MUTEX_HPP
#define CAT_MUTEX_HPP
#include <cat/Platform.hpp>
#if defined(CAT_OS_WINDOWS)
# include <cat/port/WindowsInclude.hpp>
#else // use POSIX mutex library otherwise
# include <pthread.h>
#endif
namespace cat {
// Implements a mutex that is NOT reentrant (for speed)
class Mutex
{
#if defined(CAT_OS_WINDOWS)
CRITICAL_SECTION cs;
#else
int init_failure;
pthread_mutex_t mx;
#endif
public:
Mutex();
~Mutex();
bool Valid();
bool Enter();
bool Leave();
};
class AutoMutex
{
Mutex *_mutex;
public:
AutoMutex(Mutex &mutex);
~AutoMutex();
bool Release();
};
} // namespace cat
#endif // CAT_MUTEX_HPP

View File

@ -0,0 +1,93 @@
/*
Copyright (c) 2009-2010 Christopher A. Taylor. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of LibCat nor the names of its contributors may be used
to endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef CAT_RW_LOCK_HPP
#define CAT_RW_LOCK_HPP
#include <cat/threads/Mutex.hpp>
namespace cat {
//// RWLock
class RWLock
{
#if defined(CAT_OS_WINDOWS)
volatile u32 _rd_count;
volatile u32 _wr_count;
HANDLE _rd_event;
Mutex _wr_lock;
#else
int init_failure;
pthread_rwlock_t rw;
#endif
public:
RWLock();
~RWLock();
void ReadLock();
void ReadUnlock();
void WriteLock();
void WriteUnlock();
};
//// AutoReadLock
class AutoReadLock
{
RWLock *_lock;
public:
AutoReadLock(RWLock &lock);
~AutoReadLock();
bool Release();
};
//// AutoWriteLock
class AutoWriteLock
{
RWLock *_lock;
public:
AutoWriteLock(RWLock &lock);
~AutoWriteLock();
bool Release();
};
} // namespace cat
#endif // CAT_RW_LOCK_HPP

View File

@ -0,0 +1,205 @@
/*
Copyright (c) 2009-2010 Christopher A. Taylor. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of LibCat nor the names of its contributors may be used
to endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef CAT_REGION_ALLOCATOR_HPP
#define CAT_REGION_ALLOCATOR_HPP
#include <cat/Singleton.hpp>
#include <memory>
#include <xstring>
#include <sstream>
namespace cat {
// A region-based allocator that is lock-free, supporting
// a range of allocation block sizes that are pre-allocated
// in a pre-determined way, tuned to the application.
class RegionAllocator : public Singleton<RegionAllocator>
{
CAT_SINGLETON(RegionAllocator);
protected:
struct RegionInfoHead
{
u32 next_bitmap_entry;
};
struct RegionInfo : public RegionInfoHead
{
volatile u32 bitmap[1];
};
// 64, 128, 256, 512, 1024, 2048 only
static const u32 REGION_COUNT = 6;
static const u32 BLOCK_SIZE[REGION_COUNT];
u32 bytes_overall;
u32 blocks_per_region[REGION_COUNT];
u32 bitmap_dwords[REGION_COUNT];
u8 *regions[REGION_COUNT];
RegionInfo *region_info[REGION_COUNT];
//u32 errors;
public:
bool Valid();
void Shutdown();
public:
void *Acquire(u32 bytes);
void *Resize(void *ptr, u32 bytes);
void Release(void *ptr);
template<class T>
CAT_INLINE void Delete(T *ptr)
{
ptr->~T();
Release(ptr);
}
// Acquires a buffer from the allocator that is the size of the type.
// It further allocates a number of extra bytes beyond the end of the buffer.
// Release the buffer with:
// RegionAllocator::ii->Release(ptr);
template<class T> T *AcquireBuffer(u32 extra_bytes = 0)
{
return reinterpret_cast<T*>( Acquire(sizeof(T) + extra_bytes) );
}
};
// Use STLRegionAllocator in place of the standard STL allocator
// to make use of the RegionAllocator in STL types. Some common
// usage typedefs follow this class definition below.
template<typename T>
class STLRegionAllocator
{
public:
typedef size_t size_type;
typedef size_t difference_type;
typedef T *pointer;
typedef const T *const_pointer;
typedef T &reference;
typedef const T &const_reference;
typedef T value_type;
template<typename S>
struct rebind
{
typedef STLRegionAllocator<S> other;
};
pointer address(reference X) const
{
return &X;
}
const_pointer address(const_reference X) const
{
return &X;
}
STLRegionAllocator() throw ()
{
}
template<typename S>
STLRegionAllocator(const STLRegionAllocator<S> &cp) throw ()
{
}
template<typename S>
STLRegionAllocator<T> &operator=(const STLRegionAllocator<S> &cp) throw ()
{
return *this;
}
pointer allocate(size_type Count, const void *Hint = 0)
{
return (pointer)RegionAllocator::ii->Acquire((u32)Count * sizeof(T));
}
void deallocate(pointer Ptr, size_type Count)
{
RegionAllocator::ii->Release(Ptr);
}
void construct(pointer Ptr, const T &Val)
{
std::_Construct(Ptr, Val);
}
void destroy(pointer Ptr)
{
std::_Destroy(Ptr);
}
size_type max_size() const
{
return 0x00FFFFFF;
}
template<typename S>
bool operator==(STLRegionAllocator <S> const &) const throw()
{
return true;
}
template<typename S>
bool operator!=(STLRegionAllocator <S> const &) const throw()
{
return false;
}
};
// Common usage typedefs for using RegionAllocator as the STL allocator
typedef std::basic_ostringstream<char, std::char_traits<char>, STLRegionAllocator<char> > region_ostringstream;
typedef std::basic_string<char, std::char_traits<char>, STLRegionAllocator<char> > region_string;
} // namespace cat
// Provide placement new constructor and delete pair to allow for
// an easy syntax to create objects from the RegionAllocator:
// T *a = new (RegionAllocator::ii) T();
// The object can be freed with:
// RegionAllocator::ii->Delete(a);
// Which insures that the destructor is called before freeing memory
inline void *operator new(size_t bytes, cat::RegionAllocator *allocator)
{
return allocator->Acquire((cat::u32)bytes);
}
inline void operator delete(void *ptr, cat::RegionAllocator *allocator)
{
allocator->Release(ptr);
}
#endif // CAT_REGION_ALLOCATOR_HPP

View File

@ -0,0 +1,80 @@
/*
Copyright (c) 2009-2010 Christopher A. Taylor. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of LibCat nor the names of its contributors may be used
to endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef CAT_THREAD_HPP
#define CAT_THREAD_HPP
#include <cat/Platform.hpp>
#if defined(CAT_OS_WINDOWS)
# include <cat/port/WindowsInclude.hpp>
#else // use POSIX thread library otherwise
# include <pthread.h>
#endif
namespace cat {
/*
A thread that executes ThreadFunction and then exits.
Derive from this class and implement ThreadFunction().
*/
class Thread
{
protected:
void *caller_param;
volatile bool _thread_running;
#if defined(CAT_OS_WINDOWS)
volatile HANDLE _thread;
static unsigned int __stdcall ThreadWrapper(void *this_object);
#else
pthread_t _thread;
static void *ThreadWrapper(void *this_object);
#endif
public:
bool StartThread(void *param = 0);
bool WaitForThread(int milliseconds = -1); // < 0 = infinite wait
void AbortThread();
CAT_INLINE bool ThreadRunning() { return _thread_running; }
protected:
virtual bool ThreadFunction(void *param) = 0;
public:
Thread();
CAT_INLINE virtual ~Thread() {}
};
} // namespace cat
#endif // CAT_THREAD_HPP

View File

@ -0,0 +1,221 @@
/*
Copyright (c) 2009-2010 Christopher A. Taylor. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of LibCat nor the names of its contributors may be used
to endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef CAT_THREAD_POOL_HPP
#define CAT_THREAD_POOL_HPP
#include <cat/Singleton.hpp>
#include <cat/threads/Mutex.hpp>
#include <cat/crypt/tunnel/KeyAgreement.hpp>
#include <cat/threads/RegionAllocator.hpp>
#include <cat/io/AsyncBuffer.hpp>
#include <cat/threads/Thread.hpp>
#include <cat/threads/WaitableFlag.hpp>
#if defined(CAT_OS_WINDOWS)
# include <cat/port/WindowsInclude.hpp>
#endif
namespace cat {
// Reference Object priorities
enum RefObjectPriorities
{
REFOBJ_PRIO_0,
REFOBJ_PRIO_COUNT = 32,
};
/*
class ThreadRefObject
Base class for any thread-safe reference-counted thread pool object
Designed this way so that all of these objects can be automatically deleted
*/
class ThreadRefObject
{
friend class ThreadPool;
ThreadRefObject *last, *next;
int _priorityLevel;
volatile u32 _refCount;
public:
ThreadRefObject(int priorityLevel);
CAT_INLINE virtual ~ThreadRefObject() {}
public:
void AddRef();
void ReleaseRef();
// Safe release -- If not null, then releases and sets to null
template<class T>
static CAT_INLINE void SafeRelease(T * &object)
{
if (object)
{
object->ReleaseRef();
object = 0;
}
}
};
// Auto release for ThreadRefObject references
template<class T>
class AutoRef
{
T *_ref;
public:
CAT_INLINE AutoRef(T *ref = 0) throw() { _ref = ref; }
CAT_INLINE ~AutoRef() throw() { ThreadRefObject::SafeRelease(_ref); }
CAT_INLINE AutoRef &operator=(T *ref) throw() { Reset(ref); return *this; }
CAT_INLINE T *Get() throw() { return _ref; }
CAT_INLINE T *operator->() throw() { return _ref; }
CAT_INLINE T &operator*() throw() { return *_ref; }
CAT_INLINE operator T*() { return _ref; }
CAT_INLINE void Forget() throw() { _ref = 0; }
CAT_INLINE void Reset(T *ref = 0) throw() { ThreadRefObject::SafeRelease(_ref); _ref = ref; }
};
//// TLS
class ThreadPoolLocalStorage
{
public:
BigTwistedEdwards *math;
FortunaOutput *csprng;
ThreadPoolLocalStorage();
~ThreadPoolLocalStorage();
bool Valid();
};
//// Shutdown
class ShutdownWait;
class ShutdownObserver;
class ShutdownWait
{
friend class ShutdownObserver;
WaitableFlag _kill_flag;
ShutdownObserver *_observer;
void OnShutdownDone();
public:
// Priority number must be higher than users'
ShutdownWait(int priorityLevel);
/*virtual*/ ~ShutdownWait();
CAT_INLINE ShutdownObserver *GetObserver() { return _observer; }
bool WaitForShutdown(u32 milliseconds);
};
class ShutdownObserver : public ThreadRefObject
{
friend class ShutdownWait;
ShutdownWait *_wait;
private:
ShutdownObserver(int priorityLevel, ShutdownWait *wait);
~ShutdownObserver();
};
//// ThreadPoolWorker
class ThreadPoolWorker : public Thread
{
public:
virtual bool ThreadFunction(void *port);
};
#if defined(CAT_OS_WINDOWS)
typedef HANDLE ThreadPoolHandle;
#else
typedef int ThreadPoolHandle;
#endif
/*
class ThreadPool
Startup() : Call to start up the thread pool
Shutdown() : Call to destroy the thread pool and objects
*/
class ThreadPool : public Singleton<ThreadPool>
{
friend class ThreadRefObject;
CAT_SINGLETON(ThreadPool);
#if defined(CAT_OS_WINDOWS)
HANDLE _port;
#endif
int _processor_count, _active_thread_count;
static const int MAX_THREADS = 256;
ThreadPoolWorker _threads[MAX_THREADS];
// Track sockets for graceful termination
Mutex _objectRefLock[REFOBJ_PRIO_COUNT];
ThreadRefObject *_objectRefHead[REFOBJ_PRIO_COUNT];
protected:
void TrackObject(ThreadRefObject *object);
void UntrackObject(ThreadRefObject *object);
bool SpawnThread();
bool SpawnThreads();
public:
bool Startup();
void Shutdown();
bool Associate(ThreadPoolHandle h, ThreadRefObject *key);
int GetProcessorCount() { return _processor_count; }
int GetThreadCount() { return _active_thread_count; }
};
} // namespace cat
#endif // CAT_THREAD_POOL_HPP

View File

@ -0,0 +1,92 @@
/*
Copyright (c) 2009-2010 Christopher A. Taylor. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of LibCat nor the names of its contributors may be used
to endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef CAT_WAITABLE_FLAG_HPP
#define CAT_WAITABLE_FLAG_HPP
#include <cat/Platform.hpp>
#if defined(CAT_OS_WINDOWS)
# include <cat/port/WindowsInclude.hpp>
#else // use POSIX thread library otherwise
# include <pthread.h>
#endif
namespace cat {
/*
class WaitableFlag
Can be set, reset or waited upon.
Initially unset.
Flag is edge-triggered.
Successful waiting will reset the flag.
Only one thread can wait at a time.
Designed to synchronize threads:
One thread can wait for this flag to be raised by another thread before continuing.
*/
class WaitableFlag
{
#if defined(CAT_OS_WINDOWS)
HANDLE _event;
#else
bool _valid, _valid_cond, _valid_mutex;
volatile u32 _flag;
pthread_cond_t _cond;
pthread_mutex_t _mutex;
#endif
void Cleanup();
public:
WaitableFlag();
CAT_INLINE virtual ~WaitableFlag()
{
Cleanup();
}
CAT_INLINE bool Valid()
{
#if defined(CAT_OS_WINDOWS)
return _event != 0;
#else
return _valid;
#endif
}
bool Set();
bool Wait(int milliseconds = -1); // < 0 = wait forever
};
} // namespace cat
#endif // CAT_WAITABLE_FLAG_HPP