├── .gitattributes ├── .gitignore ├── Benchmarks ├── Common │ └── Timer.h ├── ParallelThreadRing │ ├── ParallelThreadRing.cpp │ ├── ParallelThreadRing.vcxproj │ └── ParallelThreadRing.vcxproj.filters ├── PingPong │ ├── PingPong.cpp │ ├── PingPong.vcxproj │ └── PingPong.vcxproj.filters ├── PrimeFactors │ ├── PrimeFactors.cpp │ ├── PrimeFactors.vcxproj │ └── PrimeFactors.vcxproj.filters └── ThreadRing │ ├── ThreadRing.cpp │ ├── ThreadRing.vcxproj │ └── ThreadRing.vcxproj.filters ├── Include ├── External │ ├── Standard │ │ ├── inttypes.h │ │ └── stdint.h │ └── boost │ │ ├── atomic.hpp │ │ └── atomic │ │ ├── detail │ │ ├── base.hpp │ │ ├── cas32strong.hpp │ │ ├── cas32weak.hpp │ │ ├── cas64strong.hpp │ │ ├── gcc-alpha.hpp │ │ ├── gcc-armv6+.hpp │ │ ├── gcc-cas.hpp │ │ ├── gcc-ppc.hpp │ │ ├── gcc-x86.hpp │ │ ├── generic-cas.hpp │ │ ├── interlocked.hpp │ │ ├── linux-arm.hpp │ │ └── type-classifier.hpp │ │ └── platform.hpp └── Theron │ ├── Actor.h │ ├── Address.h │ ├── Align.h │ ├── AllocatorManager.h │ ├── Assert.h │ ├── BasicTypes.h │ ├── Catcher.h │ ├── DefaultAllocator.h │ ├── Defines.h │ ├── Detail │ ├── Alignment │ │ └── MessageAlignment.h │ ├── Allocators │ │ ├── CachingAllocator.h │ │ └── Pool.h │ ├── Containers │ │ ├── List.h │ │ ├── Map.h │ │ └── Queue.h │ ├── Debug │ │ └── BuildDescriptor.h │ ├── Directory │ │ ├── Directory.h │ │ ├── Entry.h │ │ └── StaticDirectory.h │ ├── Handlers │ │ ├── BlindDefaultHandler.h │ │ ├── BlindFallbackHandler.h │ │ ├── DefaultFallbackHandler.h │ │ ├── DefaultHandler.h │ │ ├── DefaultHandlerCollection.h │ │ ├── FallbackHandler.h │ │ ├── FallbackHandlerCollection.h │ │ ├── HandlerCollection.h │ │ ├── IDefaultHandler.h │ │ ├── IFallbackHandler.h │ │ ├── IMessageHandler.h │ │ ├── IReceiverHandler.h │ │ ├── MessageHandler.h │ │ ├── MessageHandlerCast.h │ │ ├── ReceiverHandler.h │ │ └── ReceiverHandlerCast.h │ ├── Mailboxes │ │ └── Mailbox.h │ ├── Messages │ │ ├── IMessage.h │ │ ├── Message.h │ │ ├── MessageCast.h │ │ ├── MessageCreator.h │ │ ├── MessageSize.h │ │ └── MessageTraits.h │ ├── Network │ │ ├── Index.h │ │ ├── MessageFactory.h │ │ ├── NameGenerator.h │ │ ├── NameMap.h │ │ └── NetworkMessage.h │ ├── Scheduler │ │ ├── BlockingMonitor.h │ │ ├── Counting.h │ │ ├── IScheduler.h │ │ ├── MailboxContext.h │ │ ├── MailboxProcessor.h │ │ ├── MailboxQueue.h │ │ ├── NonBlockingMonitor.h │ │ ├── Scheduler.h │ │ ├── SchedulerHints.h │ │ ├── ThreadPool.h │ │ ├── WorkerContext.h │ │ ├── YieldImplementation.h │ │ └── YieldPolicy.h │ ├── Strings │ │ ├── String.h │ │ ├── StringHash.h │ │ └── StringPool.h │ ├── Threading │ │ ├── Atomic.h │ │ ├── Clock.h │ │ ├── Condition.h │ │ ├── Lock.h │ │ ├── Mutex.h │ │ ├── README.txt │ │ ├── SpinLock.h │ │ ├── Thread.h │ │ └── Utils.h │ └── Transport │ │ ├── Context.h │ │ ├── InputMessage.h │ │ ├── InputSocket.h │ │ ├── OutputMessage.h │ │ └── OutputSocket.h │ ├── EndPoint.h │ ├── Framework.h │ ├── IAllocator.h │ ├── Receiver.h │ ├── Register.h │ ├── Theron.h │ └── YieldStrategy.h ├── LICENSE.txt ├── Lib └── README.txt ├── README.md ├── README.txt ├── Tests ├── TestFramework │ ├── ITestSuite.h │ ├── TestException.h │ ├── TestManager.h │ └── TestSuite.h ├── TestSuites │ ├── FeatureTestSuite.h │ └── NetworkTestSuite.h ├── Tests.cpp ├── Tests.vcxproj └── Tests.vcxproj.filters ├── Theron.doxy ├── Theron.sln ├── Theron ├── Actor.cpp ├── Address.cpp ├── AllocatorManager.cpp ├── BuildDescriptor.cpp ├── Clock.cpp ├── DefaultHandlerCollection.cpp ├── EndPoint.cpp ├── FallbackHandlerCollection.cpp ├── Framework.cpp ├── HandlerCollection.cpp ├── Properties │ └── Theron.props ├── Receiver.cpp ├── StringPool.cpp ├── Theron.vcxproj ├── Theron.vcxproj.filters ├── YieldPolicy.cpp └── mainpage.txt ├── Tutorial ├── Alignment │ ├── Alignment.cpp │ ├── Alignment.vcxproj │ └── Alignment.vcxproj.filters ├── Client │ ├── Client.cpp │ ├── Client.vcxproj │ └── Client.vcxproj.filters ├── Common │ └── Utils.h ├── CustomAllocators │ ├── CustomAllocators.cpp │ ├── CustomAllocators.vcxproj │ └── CustomAllocators.vcxproj.filters ├── FileReader │ ├── FileReader.cpp │ ├── FileReader.vcxproj │ └── FileReader.vcxproj.filters ├── HelloWorld │ ├── HelloWorld.cpp │ ├── HelloWorld.vcxproj │ └── HelloWorld.vcxproj.filters ├── MessageRegistration │ ├── MessageRegistration.cpp │ ├── MessageRegistration.vcxproj │ └── MessageRegistration.vcxproj.filters ├── Server │ ├── Server.cpp │ ├── Server.vcxproj │ └── Server.vcxproj.filters └── UnhandledMessages │ ├── UnhandledMessages.cpp │ ├── UnhandledMessages.vcxproj │ └── UnhandledMessages.vcxproj.filters └── makefile /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | 4 | # Custom for Visual Studio 5 | *.cs diff=csharp 6 | *.sln merge=union 7 | *.csproj merge=union 8 | *.vbproj merge=union 9 | *.fsproj merge=union 10 | *.dbproj merge=union 11 | 12 | # Standard to msysgit 13 | *.doc diff=astextplain 14 | *.DOC diff=astextplain 15 | *.docx diff=astextplain 16 | *.DOCX diff=astextplain 17 | *.dot diff=astextplain 18 | *.DOT diff=astextplain 19 | *.pdf diff=astextplain 20 | *.PDF diff=astextplain 21 | *.rtf diff=astextplain 22 | *.RTF diff=astextplain 23 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ################# 2 | ## Eclipse 3 | ################# 4 | 5 | *.pydevproject 6 | .project 7 | .metadata 8 | bin/ 9 | tmp/ 10 | *.tmp 11 | *.bak 12 | *.swp 13 | *~.nib 14 | local.properties 15 | .classpath 16 | .settings/ 17 | .loadpath 18 | 19 | # External tool builders 20 | .externalToolBuilders/ 21 | 22 | # Locally stored "Eclipse launch configurations" 23 | *.launch 24 | 25 | # CDT-specific 26 | .cproject 27 | 28 | # PDT-specific 29 | .buildpath 30 | 31 | 32 | ################# 33 | ## Visual Studio 34 | ################# 35 | 36 | ## Ignore Visual Studio temporary files, build results, and 37 | ## files generated by popular Visual Studio add-ons. 38 | 39 | # User-specific files 40 | *.suo 41 | *.user 42 | *.sln.docstates 43 | 44 | # Build results 45 | *_i.c 46 | *_p.c 47 | *.ilk 48 | *.meta 49 | *.obj 50 | *.pch 51 | *.pdb 52 | *.pgc 53 | *.pgd 54 | *.rsp 55 | *.sbr 56 | *.tlb 57 | *.tli 58 | *.tlh 59 | *.tmp 60 | *.vspscc 61 | .builds 62 | *.dotCover 63 | 64 | ## TODO: If you have NuGet Package Restore enabled, uncomment this 65 | #packages/ 66 | 67 | # Visual C++ cache files 68 | ipch/ 69 | *.aps 70 | *.ncb 71 | *.opensdf 72 | *.sdf 73 | 74 | # Visual Studio profiler 75 | *.psess 76 | *.vsp 77 | 78 | # ReSharper is a .NET coding add-in 79 | _ReSharper* 80 | 81 | # Installshield output folder 82 | [Ee]xpress 83 | 84 | # DocProject is a documentation generator add-in 85 | DocProject/buildhelp/ 86 | DocProject/Help/*.HxT 87 | DocProject/Help/*.HxC 88 | DocProject/Help/*.hhc 89 | DocProject/Help/*.hhk 90 | DocProject/Help/*.hhp 91 | DocProject/Help/Html2 92 | DocProject/Help/html 93 | 94 | # Click-Once directory 95 | publish 96 | 97 | # Others 98 | [Bb]in 99 | [Oo]bj 100 | sql 101 | TestResults 102 | *.Cache 103 | ClientBin 104 | stylecop.* 105 | ~$* 106 | *.dbmdl 107 | Generated_Code #added for RIA/Silverlight projects 108 | 109 | # Backup & report files from converting an old project file to a newer 110 | # Visual Studio version. Backup files are not needed, because we have git ;-) 111 | _UpgradeReport_Files/ 112 | Backup*/ 113 | UpgradeLog*.XML 114 | 115 | 116 | 117 | ############ 118 | ## Windows 119 | ############ 120 | 121 | # Windows image file caches 122 | Thumbs.db 123 | 124 | # Folder config file 125 | Desktop.ini 126 | 127 | 128 | ############# 129 | ## Python 130 | ############# 131 | 132 | *.py[co] 133 | 134 | # Packages 135 | *.egg 136 | *.egg-info 137 | dist 138 | build 139 | eggs 140 | parts 141 | bin 142 | var 143 | sdist 144 | develop-eggs 145 | .installed.cfg 146 | 147 | # Installer logs 148 | pip-log.txt 149 | 150 | # Unit test / coverage reports 151 | .coverage 152 | .tox 153 | 154 | #Translations 155 | *.mo 156 | 157 | #Mr Developer 158 | .mr.developer.cfg 159 | 160 | # Mac crap 161 | .DS_Store 162 | -------------------------------------------------------------------------------- /Benchmarks/Common/Timer.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) by Ashton Mason. See LICENSE.txt for licensing information. 2 | #ifndef THERON_BENCHMARKS_COMMON_TIMER_H 3 | #define THERON_BENCHMARKS_COMMON_TIMER_H 4 | 5 | 6 | #include 7 | 8 | 9 | #if THERON_WINDOWS 10 | #include 11 | #elif THERON_GCC 12 | #include 13 | #endif 14 | 15 | 16 | // Simple timer class. 17 | class Timer 18 | { 19 | public: 20 | 21 | Timer() : mSupported(false) 22 | { 23 | #if THERON_WINDOWS 24 | // Read the counter frequency (in Hz) and an initial counter value. 25 | if (QueryPerformanceFrequency(&mTicksPerSecond) && QueryPerformanceCounter(&mCounterStartValue)) 26 | { 27 | mSupported = true; 28 | } 29 | #elif THERON_GCC 30 | mSupported = true; 31 | #endif 32 | } 33 | 34 | void Start() 35 | { 36 | #if THERON_WINDOWS 37 | QueryPerformanceCounter(&mCounterStartValue); 38 | #elif THERON_GCC 39 | gettimeofday(&t1, NULL); 40 | #endif 41 | } 42 | 43 | void Stop() 44 | { 45 | #if THERON_WINDOWS 46 | QueryPerformanceCounter(&mCounterEndValue); 47 | #elif THERON_GCC 48 | gettimeofday(&t2, NULL); 49 | #endif 50 | } 51 | 52 | bool Supported() const 53 | { 54 | return mSupported; 55 | } 56 | 57 | float Seconds() const 58 | { 59 | #if THERON_WINDOWS 60 | const float elapsedTicks(static_cast(mCounterEndValue.QuadPart - mCounterStartValue.QuadPart)); 61 | const float ticksPerSecond(static_cast(mTicksPerSecond.QuadPart)); 62 | return (elapsedTicks / ticksPerSecond); 63 | #elif THERON_GCC 64 | return (t2.tv_sec - t1.tv_sec) + (t2.tv_usec - t1.tv_usec) * 1e-6f; 65 | #else 66 | return 0.0f; 67 | #endif 68 | } 69 | 70 | private: 71 | 72 | Timer(const Timer &other); 73 | Timer &operator=(const Timer &other); 74 | 75 | bool mSupported; 76 | 77 | #if THERON_WINDOWS 78 | LARGE_INTEGER mTicksPerSecond; 79 | LARGE_INTEGER mCounterStartValue; 80 | LARGE_INTEGER mCounterEndValue; 81 | #elif THERON_GCC 82 | timeval t1, t2; 83 | #endif 84 | 85 | }; 86 | 87 | 88 | #endif // THERON_BENCHMARKS_COMMON_TIMER_H 89 | 90 | -------------------------------------------------------------------------------- /Benchmarks/ParallelThreadRing/ParallelThreadRing.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hpp;hxx;hm;inl;inc;xsd 11 | 12 | 13 | 14 | 15 | Source Files 16 | 17 | 18 | 19 | 20 | Header Files 21 | 22 | 23 | -------------------------------------------------------------------------------- /Benchmarks/PingPong/PingPong.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hpp;hxx;hm;inl;inc;xsd 11 | 12 | 13 | 14 | 15 | Source Files 16 | 17 | 18 | 19 | 20 | Header Files 21 | 22 | 23 | -------------------------------------------------------------------------------- /Benchmarks/PrimeFactors/PrimeFactors.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hpp;hxx;hm;inl;inc;xsd 11 | 12 | 13 | 14 | 15 | Header Files 16 | 17 | 18 | 19 | 20 | Source Files 21 | 22 | 23 | -------------------------------------------------------------------------------- /Benchmarks/ThreadRing/ThreadRing.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hpp;hxx;hm;inl;inc;xsd 11 | 12 | 13 | 14 | 15 | Header Files 16 | 17 | 18 | 19 | 20 | Source Files 21 | 22 | 23 | -------------------------------------------------------------------------------- /Include/External/boost/atomic/detail/gcc-cas.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2011 Helge Bahmann 2 | // 3 | // Distributed under the Boost Software License, Version 1.0. 4 | // See accompanying file LICENSE_1_0.txt or copy at 5 | // http://www.boost.org/LICENSE_1_0.txt) 6 | 7 | // Use the gnu builtin __sync_val_compare_and_swap to build 8 | // atomic operations for 32 bit and smaller. 9 | 10 | #ifndef BOOST_DETAIL_ATOMIC_GENERIC_CAS_HPP 11 | #define BOOST_DETAIL_ATOMIC_GENERIC_CAS_HPP 12 | 13 | #define BOOST_ATOMIC_CHAR_LOCK_FREE 2 14 | #define BOOST_ATOMIC_SHORT_LOCK_FREE 2 15 | #define BOOST_ATOMIC_INT_LOCK_FREE 2 16 | #define BOOST_ATOMIC_LONG_LOCK_FREE (sizeof(long) <= 4 ? 2 : 0) 17 | #define BOOST_ATOMIC_LLONG_LOCK_FREE (sizeof(long long) <= 4 ? 2 : 0) 18 | #define BOOST_ATOMIC_ADDRESS_LOCK_FREE (sizeof(void *) <= 4 ? 2 : 0) 19 | #define BOOST_ATOMIC_BOOL_LOCK_FREE 2 20 | 21 | namespace boost { 22 | 23 | #define BOOST_ATOMIC_THREAD_FENCE 2 24 | inline void 25 | atomic_thread_fence(memory_order order) 26 | { 27 | switch(order) { 28 | case memory_order_relaxed: 29 | break; 30 | case memory_order_release: 31 | case memory_order_consume: 32 | case memory_order_acquire: 33 | case memory_order_acq_rel: 34 | case memory_order_seq_cst: 35 | __sync_synchronize(); 36 | break; 37 | } 38 | } 39 | 40 | namespace detail { 41 | namespace atomic { 42 | 43 | static inline void 44 | platform_fence_before(memory_order) 45 | { 46 | /* empty, as compare_and_swap is synchronizing already */ 47 | } 48 | 49 | static inline void 50 | platform_fence_after(memory_order) 51 | { 52 | /* empty, as compare_and_swap is synchronizing already */ 53 | } 54 | 55 | static inline void 56 | platform_fence_before_store(memory_order order) 57 | { 58 | switch(order) { 59 | case memory_order_relaxed: 60 | case memory_order_acquire: 61 | case memory_order_consume: 62 | break; 63 | case memory_order_release: 64 | case memory_order_acq_rel: 65 | case memory_order_seq_cst: 66 | __sync_synchronize(); 67 | break; 68 | } 69 | } 70 | 71 | static inline void 72 | platform_fence_after_store(memory_order order) 73 | { 74 | if (order == memory_order_seq_cst) 75 | __sync_synchronize(); 76 | } 77 | 78 | static inline void 79 | platform_fence_after_load(memory_order order) 80 | { 81 | switch(order) { 82 | case memory_order_relaxed: 83 | case memory_order_release: 84 | break; 85 | case memory_order_consume: 86 | case memory_order_acquire: 87 | case memory_order_acq_rel: 88 | case memory_order_seq_cst: 89 | __sync_synchronize(); 90 | break; 91 | } 92 | } 93 | 94 | template 95 | bool 96 | platform_cmpxchg32_strong(T & expected, T desired, volatile T * ptr) 97 | { 98 | T found = __sync_val_compare_and_swap(ptr, expected, desired); 99 | bool success = (found == expected); 100 | expected = found; 101 | return success; 102 | } 103 | 104 | } 105 | } 106 | } 107 | 108 | #include 109 | 110 | #endif 111 | -------------------------------------------------------------------------------- /Include/External/boost/atomic/detail/interlocked.hpp: -------------------------------------------------------------------------------- 1 | #ifndef BOOST_DETAIL_ATOMIC_INTERLOCKED_HPP 2 | #define BOOST_DETAIL_ATOMIC_INTERLOCKED_HPP 3 | 4 | // Copyright (c) 2009 Helge Bahmann 5 | // 6 | // Distributed under the Boost Software License, Version 1.0. 7 | // See accompanying file LICENSE_1_0.txt or copy at 8 | // http://www.boost.org/LICENSE_1_0.txt) 9 | 10 | #include 11 | 12 | #define BOOST_ATOMIC_CHAR_LOCK_FREE 2 13 | #define BOOST_ATOMIC_SHORT_LOCK_FREE 2 14 | #define BOOST_ATOMIC_INT_LOCK_FREE 2 15 | #define BOOST_ATOMIC_LONG_LOCK_FREE (sizeof(long) <= 4 ? 2 : 0) 16 | #define BOOST_ATOMIC_LLONG_LOCK_FREE (sizeof(long long) <= 4 ? 2 : 0) 17 | #define BOOST_ATOMIC_ADDRESS_LOCK_FREE (sizeof(void *) <= 4 ? 2 : 0) 18 | #define BOOST_ATOMIC_BOOL_LOCK_FREE 2 19 | 20 | namespace boost { 21 | namespace detail { 22 | namespace atomic { 23 | 24 | static inline void 25 | x86_full_fence(void) 26 | { 27 | long tmp; 28 | BOOST_INTERLOCKED_EXCHANGE(&tmp, 0); 29 | } 30 | 31 | static inline void 32 | platform_fence_before(memory_order) 33 | { 34 | } 35 | 36 | static inline void 37 | platform_fence_after(memory_order) 38 | { 39 | } 40 | 41 | static inline void 42 | platform_fence_before_store(memory_order) 43 | { 44 | } 45 | 46 | static inline void 47 | platform_fence_after_store(memory_order order) 48 | { 49 | if (order == memory_order_seq_cst) 50 | x86_full_fence(); 51 | } 52 | 53 | static inline void 54 | platform_fence_after_load(memory_order order) 55 | { 56 | if (order == memory_order_seq_cst) { 57 | x86_full_fence(); 58 | } 59 | } 60 | 61 | template 62 | bool 63 | platform_cmpxchg32_strong(T & expected, T desired, volatile T * ptr) 64 | { 65 | T prev = expected; 66 | expected = (T)BOOST_INTERLOCKED_COMPARE_EXCHANGE((long *)(ptr), (long)desired, (long)expected); 67 | bool success = (prev==expected); 68 | return success; 69 | } 70 | 71 | #if defined(_WIN64) 72 | template 73 | bool 74 | platform_cmpxchg64_strong(T & expected, T desired, volatile T * ptr) 75 | { 76 | T prev = expected; 77 | expected = (T) _InterlockedCompareExchange64((long long *)(ptr), (long long)desired, (long long)expected); 78 | bool success = (prev==expected); 79 | return success; 80 | } 81 | #endif 82 | 83 | } 84 | } 85 | 86 | #define BOOST_ATOMIC_THREAD_FENCE 2 87 | inline void 88 | atomic_thread_fence(memory_order order) 89 | { 90 | if (order == memory_order_seq_cst) { 91 | detail::atomic::x86_full_fence(); 92 | } 93 | } 94 | 95 | } 96 | 97 | #include 98 | 99 | #endif 100 | -------------------------------------------------------------------------------- /Include/External/boost/atomic/detail/linux-arm.hpp: -------------------------------------------------------------------------------- 1 | #ifndef BOOST_DETAIL_ATOMIC_LINUX_ARM_HPP 2 | #define BOOST_DETAIL_ATOMIC_LINUX_ARM_HPP 3 | 4 | // Distributed under the Boost Software License, Version 1.0. 5 | // See accompanying file LICENSE_1_0.txt or copy at 6 | // http://www.boost.org/LICENSE_1_0.txt) 7 | // 8 | // Copyright (c) 2009, 2011 Helge Bahmann 9 | // Copyright (c) 2009 Phil Endecott 10 | // Linux-specific code by Phil Endecott 11 | 12 | // Different ARM processors have different atomic instructions. In particular, 13 | // architecture versions before v6 (which are still in widespread use, e.g. the 14 | // Intel/Marvell XScale chips like the one in the NSLU2) have only atomic swap. 15 | // On Linux the kernel provides some support that lets us abstract away from 16 | // these differences: it provides emulated CAS and barrier functions at special 17 | // addresses that are garaunteed not to be interrupted by the kernel. Using 18 | // this facility is slightly slower than inline assembler would be, but much 19 | // faster than a system call. 20 | // 21 | // While this emulated CAS is "strong" in the sense that it does not fail 22 | // "spuriously" (i.e.: it never fails to perform the exchange when the value 23 | // found equals the value expected), it does not return the found value on 24 | // failure. To satisfy the atomic API, compare_exchange_{weak|strong} must 25 | // return the found value on failure, and we have to manually load this value 26 | // after the emulated CAS reports failure. This in turn introduces a race 27 | // between the CAS failing (due to the "wrong" value being found) and subsequently 28 | // loading (which might turn up the "right" value). From an application's 29 | // point of view this looks like "spurious failure", and therefore the 30 | // emulated CAS is only good enough to provide compare_exchange_weak 31 | // semantics. 32 | 33 | #include 34 | #include 35 | 36 | #define BOOST_ATOMIC_CHAR_LOCK_FREE 2 37 | #define BOOST_ATOMIC_CHAR16_T_LOCK_FREE 2 38 | #define BOOST_ATOMIC_CHAR32_T_LOCK_FREE 2 39 | #define BOOST_ATOMIC_WCHAR_T_LOCK_FREE 2 40 | #define BOOST_ATOMIC_SHORT_LOCK_FREE 2 41 | #define BOOST_ATOMIC_INT_LOCK_FREE 2 42 | #define BOOST_ATOMIC_LONG_LOCK_FREE 2 43 | #define BOOST_ATOMIC_LLONG_LOCK_FREE 0 44 | #define BOOST_ATOMIC_ADDRESS_LOCK_FREE 2 45 | #define BOOST_ATOMIC_BOOL_LOCK_FREE 2 46 | 47 | namespace boost { 48 | namespace detail { 49 | namespace atomic { 50 | 51 | static inline void 52 | arm_barrier(void) 53 | { 54 | void (*kernel_dmb)(void) = (void (*)(void)) 0xffff0fa0; 55 | kernel_dmb(); 56 | } 57 | 58 | static inline void 59 | platform_fence_before(memory_order order) 60 | { 61 | switch(order) { 62 | case memory_order_release: 63 | case memory_order_acq_rel: 64 | case memory_order_seq_cst: 65 | arm_barrier(); 66 | case memory_order_consume: 67 | default:; 68 | } 69 | } 70 | 71 | static inline void 72 | platform_fence_after(memory_order order) 73 | { 74 | switch(order) { 75 | case memory_order_acquire: 76 | case memory_order_acq_rel: 77 | case memory_order_seq_cst: 78 | arm_barrier(); 79 | default:; 80 | } 81 | } 82 | 83 | static inline void 84 | platform_fence_before_store(memory_order order) 85 | { 86 | platform_fence_before(order); 87 | } 88 | 89 | static inline void 90 | platform_fence_after_store(memory_order order) 91 | { 92 | if (order == memory_order_seq_cst) 93 | arm_barrier(); 94 | } 95 | 96 | static inline void 97 | platform_fence_after_load(memory_order order) 98 | { 99 | platform_fence_after(order); 100 | } 101 | 102 | template 103 | bool 104 | platform_cmpxchg32(T & expected, T desired, volatile T * ptr) 105 | { 106 | typedef T (*kernel_cmpxchg32_t)(T oldval, T newval, volatile T * ptr); 107 | 108 | if (((kernel_cmpxchg32_t) 0xffff0fc0)(expected, desired, ptr) == 0) { 109 | return true; 110 | } else { 111 | expected = *ptr; 112 | return false; 113 | } 114 | } 115 | 116 | } 117 | } 118 | 119 | #define BOOST_ATOMIC_THREAD_FENCE 2 120 | static inline void 121 | atomic_thread_fence(memory_order order) 122 | { 123 | switch(order) { 124 | case memory_order_acquire: 125 | case memory_order_release: 126 | case memory_order_acq_rel: 127 | case memory_order_seq_cst: 128 | detail::atomic::arm_barrier(); 129 | default:; 130 | } 131 | } 132 | 133 | #define BOOST_ATOMIC_SIGNAL_FENCE 2 134 | static inline void 135 | atomic_signal_fence(memory_order) 136 | { 137 | __asm__ __volatile__ ("" ::: "memory"); 138 | } 139 | 140 | } 141 | 142 | #include 143 | 144 | #endif 145 | -------------------------------------------------------------------------------- /Include/External/boost/atomic/detail/type-classifier.hpp: -------------------------------------------------------------------------------- 1 | #ifndef BOOST_DETAIL_ATOMIC_TYPE_CLASSIFIER_HPP 2 | #define BOOST_DETAIL_ATOMIC_TYPE_CLASSIFIER_HPP 3 | 4 | // Copyright (c) 2011 Helge Bahmann 5 | // 6 | // Distributed under the Boost Software License, Version 1.0. 7 | // See accompanying file LICENSE_1_0.txt or copy at 8 | // http://www.boost.org/LICENSE_1_0.txt) 9 | 10 | namespace boost { namespace detail { namespace atomic { 11 | 12 | template 13 | struct type_classifier { 14 | typedef void test; 15 | }; 16 | 17 | template<> 18 | struct type_classifier {typedef int test;}; 19 | template<> 20 | struct type_classifier {typedef int test;}; 21 | template<> 22 | struct type_classifier {typedef int test;}; 23 | template<> 24 | struct type_classifier {typedef int test;}; 25 | template<> 26 | struct type_classifier {typedef int test;}; 27 | template<> 28 | struct type_classifier {typedef int test;}; 29 | template<> 30 | struct type_classifier {typedef int test;}; 31 | template<> 32 | struct type_classifier {typedef int test;}; 33 | template<> 34 | struct type_classifier {typedef int test;}; 35 | #ifdef BOOST_HAS_LONG_LONG 36 | template<> struct type_classifier 37 | {typedef int test;}; 38 | template<> struct type_classifier 39 | {typedef int test;}; 40 | #endif 41 | 42 | template 43 | struct type_classifier {typedef void * test;}; 44 | 45 | template 46 | struct sign_trait { 47 | typedef void test; 48 | }; 49 | 50 | template<> 51 | struct sign_trait {typedef int test;}; 52 | template<> 53 | struct sign_trait {typedef unsigned int test;}; 54 | template<> 55 | struct sign_trait {typedef int test;}; 56 | template<> 57 | struct sign_trait {typedef unsigned int test;}; 58 | template<> 59 | struct sign_trait {typedef int test;}; 60 | template<> 61 | struct sign_trait {typedef unsigned int test;}; 62 | template<> 63 | struct sign_trait {typedef int test;}; 64 | template<> 65 | struct sign_trait {typedef unsigned int test;}; 66 | template<> 67 | struct sign_trait {typedef int test;}; 68 | #ifdef BOOST_HAS_LONG_LONG 69 | template<> struct sign_trait 70 | {typedef unsigned int test;}; 71 | template<> struct sign_trait 72 | {typedef int test;}; 73 | #endif 74 | 75 | 76 | 77 | }}} 78 | 79 | #endif 80 | -------------------------------------------------------------------------------- /Include/External/boost/atomic/platform.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2009 Helge Bahmann 2 | // 3 | // Distributed under the Boost Software License, Version 1.0. 4 | // See accompanying file LICENSE_1_0.txt or copy at 5 | // http://www.boost.org/LICENSE_1_0.txt) 6 | 7 | // Platform selection file 8 | 9 | #include 10 | 11 | #if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) 12 | 13 | #include 14 | 15 | #elif defined(__GNUC__) && defined(__alpha__) 16 | 17 | #include 18 | 19 | #elif defined(__GNUC__) && (defined(__POWERPC__) || defined(__PPC__)) 20 | 21 | #include 22 | 23 | // This list of ARM architecture versions comes from Apple's arm/arch.h header. 24 | // I don't know how complete it is. 25 | #elif defined(__GNUC__) && (defined(__ARM_ARCH_6__) || defined(__ARM_ARCH_6J__) \ 26 | || defined(__ARM_ARCH_6Z__) || defined(__ARM_ARCH_6ZK__) \ 27 | || defined(__ARM_ARCH_6K__) || defined(__ARM_ARCH_7A__)) 28 | 29 | #include 30 | 31 | #elif defined(__linux__) && defined(__arm__) 32 | 33 | #include 34 | 35 | #elif defined(BOOST_USE_WINDOWS_H) || defined(_WIN32_CE) || defined(BOOST_MSVC) || defined(BOOST_INTEL_WIN) || defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__CYGWIN__) 36 | 37 | #include 38 | 39 | #elif defined(__GNUC__) 40 | 41 | #include 42 | 43 | #endif 44 | -------------------------------------------------------------------------------- /Include/Theron/BasicTypes.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) by Ashton Mason. See LICENSE.txt for licensing information. 2 | #ifndef THERON_BASICTYPES_H 3 | #define THERON_BASICTYPES_H 4 | 5 | 6 | /** 7 | \file BasicTypes.h 8 | \brief Defines basic standard types in a hopefully cross-platform manner. 9 | */ 10 | 11 | 12 | #include 13 | 14 | 15 | #if THERON_BOOST 16 | 17 | // Boost provides this header. 18 | #include 19 | 20 | #elif THERON_CPP11 21 | 22 | // This header is assumed to be available in C++11 builds. 23 | #include 24 | 25 | #elif THERON_GCC 26 | 27 | // This header is typically available in GCC builds. 28 | #include 29 | 30 | #elif THERON_MSVC 31 | 32 | // MSVC 2012 and up has cstdint header 33 | #if _MSC_VER >= 1700 34 | #include 35 | #else 36 | // These are packaged with Theron, and provide stdint functionality for MSVC. 37 | #include 38 | #include 39 | #endif 40 | 41 | #else 42 | 43 | // Failing all else, we hope this C99 header is available. 44 | #include 45 | 46 | #endif 47 | 48 | 49 | namespace Theron 50 | { 51 | 52 | 53 | #if THERON_BOOST 54 | 55 | // In Boost builds we reuse the convenient Boost integer types. 56 | typedef boost::uint8_t uint8_t; 57 | typedef boost::uint32_t uint32_t; 58 | typedef boost::int32_t int32_t; 59 | typedef boost::uint64_t uint64_t; 60 | 61 | // Boost doesn't define uintptr_t so we have to define it ourselves. 62 | #if THERON_64BIT 63 | typedef unsigned long long uintptr_t; 64 | #else 65 | typedef unsigned long uintptr_t; 66 | #endif 67 | 68 | #else 69 | 70 | // Promote the global namespace types into the Theron namespace. 71 | typedef ::uint8_t uint8_t; 72 | typedef ::uint32_t uint32_t; 73 | typedef ::int32_t int32_t; 74 | typedef ::uint64_t uint64_t; 75 | typedef ::uintptr_t uintptr_t; 76 | 77 | #endif 78 | 79 | 80 | } 81 | 82 | 83 | #endif // THERON_BASICTYPES_H 84 | 85 | -------------------------------------------------------------------------------- /Include/Theron/Detail/Alignment/MessageAlignment.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) by Ashton Mason. See LICENSE.txt for licensing information. 2 | #ifndef THERON_DETAIL_ALIGNMENT_MESSAGEALIGNMENT_H 3 | #define THERON_DETAIL_ALIGNMENT_MESSAGEALIGNMENT_H 4 | 5 | 6 | #include 7 | 8 | 9 | namespace Theron 10 | { 11 | namespace Detail 12 | { 13 | 14 | 15 | /** 16 | \brief Traits struct template that stores alignment information about messages. 17 | 18 | Users can specialize this template for their own message types in order to tell 19 | Theron about any specialized alignment requirements of those classes. 20 | Theron uses the alignment value defined for each message type to request memory 21 | with the correct alignment from the general allocator registered with the 22 | \ref AllocatorManager. The default alignment is four bytes, implying that 23 | instances of the message class should be allocated starting at 4-byte boundaries. 24 | \note Note that although Theron will request memory allocated with the correct 25 | alignment, whether or not the allocator respects the alignment request is up 26 | to the allocator implementation. The default allocator, DefaultAllocator, 27 | supports alignment and returns correctly aligned allocations. Users with 28 | specialized alignment requirements should ensure that any custom allocator, 29 | implementing the \ref IAllocator interface, and enabled with 30 | \ref Theron::AllocatorManager::SetAllocator, supports aligned allocations. 31 | 32 | \tparam MessageType The message type for which the alignment traits are defined. 33 | */ 34 | template 35 | struct MessageAlignment 36 | { 37 | /** 38 | \brief Describes the memory alignment requirement of the message type, in bytes. 39 | The default alignment is four bytes. 40 | */ 41 | static const uint32_t ALIGNMENT = 4; 42 | }; 43 | 44 | 45 | } // namespace Detail 46 | } // namespace Theron 47 | 48 | 49 | #endif // THERON_DETAIL_ALIGNMENT_MESSAGEALIGNMENT_H 50 | 51 | -------------------------------------------------------------------------------- /Include/Theron/Detail/Allocators/Pool.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) by Ashton Mason. See LICENSE.txt for licensing information. 2 | #ifndef THERON_DETAIL_ALLOCATORS_POOL_H 3 | #define THERON_DETAIL_ALLOCATORS_POOL_H 4 | 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | 12 | #ifdef _MSC_VER 13 | #pragma warning(push) 14 | #pragma warning (disable:4324) // structure was padded due to __declspec(align()) 15 | #endif //_MSC_VER 16 | 17 | 18 | namespace Theron 19 | { 20 | namespace Detail 21 | { 22 | 23 | 24 | /** 25 | A pool of free memory blocks. 26 | */ 27 | template 28 | class Pool 29 | { 30 | public: 31 | 32 | /** 33 | Constructor. 34 | */ 35 | inline Pool(); 36 | 37 | /** 38 | Returns true if the pool contains no memory blocks. 39 | */ 40 | inline bool Empty() const; 41 | 42 | /** 43 | Adds a memory block to the pool. 44 | */ 45 | inline bool Add(void *memory); 46 | 47 | /** 48 | Retrieves a memory block from the pool with the given alignment. 49 | \return Zero if no suitable blocks in pool. 50 | */ 51 | inline void *FetchAligned(const uint32_t alignment); 52 | 53 | /** 54 | Retrieves a memory block from the pool with any alignment. 55 | \return Zero if no blocks in pool. 56 | */ 57 | inline void *Fetch(); 58 | 59 | private: 60 | 61 | /** 62 | A node representing a free memory block within the pool. 63 | Nodes are created in-place within the free blocks they represent. 64 | */ 65 | struct Node 66 | { 67 | THERON_FORCEINLINE Node() : mNext(0) 68 | { 69 | } 70 | 71 | Node *mNext; ///< Pointer to next node in a list. 72 | }; 73 | 74 | Node mHead; ///< Dummy node at head of a linked list of nodes in the pool. 75 | uint32_t mBlockCount; ///< Number of blocks currently cached in the pool. 76 | }; 77 | 78 | 79 | template 80 | THERON_FORCEINLINE Pool::Pool() : 81 | mHead(), 82 | mBlockCount(0) 83 | { 84 | } 85 | 86 | 87 | template 88 | THERON_FORCEINLINE bool Pool::Empty() const 89 | { 90 | THERON_ASSERT((mBlockCount == 0 && mHead.mNext == 0) || (mBlockCount != 0 && mHead.mNext != 0)); 91 | return (mBlockCount == 0); 92 | } 93 | 94 | 95 | template 96 | THERON_FORCEINLINE bool Pool::Add(void *const memory) 97 | { 98 | THERON_ASSERT(memory); 99 | 100 | // Below maximum block count limit? 101 | if (mBlockCount < MAX_BLOCKS) 102 | { 103 | // Just call it a node and link it in. 104 | Node *const node(reinterpret_cast(memory)); 105 | 106 | node->mNext = mHead.mNext; 107 | mHead.mNext = node; 108 | 109 | ++mBlockCount; 110 | return true; 111 | } 112 | 113 | return false; 114 | } 115 | 116 | 117 | template 118 | THERON_FORCEINLINE void *Pool::FetchAligned(const uint32_t alignment) 119 | { 120 | Node *previous(&mHead); 121 | const uint32_t alignmentMask(alignment - 1); 122 | 123 | // Search the block list. 124 | Node *node(mHead.mNext); 125 | while (node) 126 | { 127 | Node *const next(node->mNext); 128 | 129 | // This is the THERON_ALIGNED macro with the alignment mask calculated once outside the loop. 130 | if ((reinterpret_cast(node) & alignmentMask) == 0) 131 | { 132 | // Remove from list and return as a block. 133 | previous->mNext = next; 134 | --mBlockCount; 135 | 136 | return reinterpret_cast(node); 137 | } 138 | 139 | previous = node; 140 | node = next; 141 | } 142 | 143 | // Zero result indicates no correctly aligned block available. 144 | return 0; 145 | } 146 | 147 | 148 | template 149 | THERON_FORCEINLINE void *Pool::Fetch() 150 | { 151 | // Grab first block in the list if the list isn't empty. 152 | Node *const node(mHead.mNext); 153 | if (node) 154 | { 155 | mHead.mNext = node->mNext; 156 | --mBlockCount; 157 | 158 | return reinterpret_cast(node); 159 | } 160 | 161 | // Zero result indicates no block available. 162 | return 0; 163 | } 164 | 165 | 166 | } // namespace Detail 167 | } // namespace Theron 168 | 169 | 170 | #ifdef _MSC_VER 171 | #pragma warning(pop) 172 | #endif //_MSC_VER 173 | 174 | 175 | #endif // THERON_DETAIL_ALLOCATORS_POOL_H 176 | -------------------------------------------------------------------------------- /Include/Theron/Detail/Directory/Directory.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) by Ashton Mason. See LICENSE.txt for licensing information. 2 | #ifndef THERON_DETAIL_DIRECTORY_DIRECTORY_H 3 | #define THERON_DETAIL_DIRECTORY_DIRECTORY_H 4 | 5 | 6 | #include 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | #include 15 | 16 | 17 | namespace Theron 18 | { 19 | namespace Detail 20 | { 21 | 22 | 23 | /** 24 | A registry that maps unique indices to addressable entities. 25 | */ 26 | template 27 | class Directory 28 | { 29 | public: 30 | 31 | /** 32 | Default constructor. 33 | */ 34 | Directory(); 35 | 36 | /** 37 | Destructor. 38 | */ 39 | ~Directory(); 40 | 41 | /** 42 | Finds and claims a free index for an entity. 43 | */ 44 | uint32_t Allocate(uint32_t index = 0); 45 | 46 | /** 47 | Gets a reference to the entry with the given index. 48 | The entry contains data about the entity (if any) registered at the index. 49 | */ 50 | inline EntryType &GetEntry(const uint32_t index); 51 | 52 | private: 53 | 54 | static const uint32_t ENTRIES_PER_PAGE = 1024; ///< Number of entries in each allocated page (power of two!). 55 | static const uint32_t MAX_PAGES = 1024; ///< Maximum number of allocated pages. 56 | 57 | struct Page 58 | { 59 | EntryType mEntries[ENTRIES_PER_PAGE]; ///< Array of entries making up this page. 60 | }; 61 | 62 | Directory(const Directory &other); 63 | Directory &operator=(const Directory &other); 64 | 65 | mutable Mutex mMutex; ///< Ensures thread-safe access to the instance data. 66 | uint32_t mNextIndex; ///< Auto-incremented index to use for next registered entity. 67 | Page *mPages[MAX_PAGES]; ///< Pointers to allocated pages. 68 | }; 69 | 70 | 71 | template 72 | inline Directory::Directory() : 73 | mMutex(), 74 | mNextIndex(0) 75 | { 76 | // Clear the page table. 77 | for (uint32_t page = 0; page < MAX_PAGES; ++page) 78 | { 79 | mPages[page] = 0; 80 | } 81 | } 82 | 83 | 84 | template 85 | inline Directory::~Directory() 86 | { 87 | IAllocator *const pageAllocator(AllocatorManager::GetCache()); 88 | 89 | // Free all pages that were allocated. 90 | for (uint32_t page = 0; page < MAX_PAGES; ++page) 91 | { 92 | if (mPages[page]) 93 | { 94 | // Destruct and free. 95 | mPages[page]->~Page(); 96 | pageAllocator->Free(mPages[page], sizeof(Page)); 97 | } 98 | } 99 | } 100 | 101 | 102 | template 103 | inline uint32_t Directory::Allocate(uint32_t index) 104 | { 105 | mMutex.Lock(); 106 | 107 | // Auto-allocate an index if none was specified. 108 | if (index == 0) 109 | { 110 | // TODO: Avoid in-use indices and re-use freed ones. 111 | // Skip index zero as it's reserved for use as the null address. 112 | if (++mNextIndex == MAX_PAGES * ENTRIES_PER_PAGE) 113 | { 114 | mNextIndex = 1; 115 | } 116 | 117 | index = mNextIndex; 118 | } 119 | 120 | // Allocate the page if it hasn't been allocated already. 121 | const uint32_t page(index / ENTRIES_PER_PAGE); 122 | if (mPages[page] == 0) 123 | { 124 | IAllocator *const pageAllocator(AllocatorManager::GetCache()); 125 | void *const pageMemory(pageAllocator->AllocateAligned(sizeof(Page), THERON_CACHELINE_ALIGNMENT)); 126 | 127 | if (pageMemory) 128 | { 129 | mPages[page] = new (pageMemory) Page(); 130 | } 131 | else 132 | { 133 | THERON_FAIL_MSG("Out of memory"); 134 | } 135 | } 136 | 137 | mMutex.Unlock(); 138 | 139 | return index; 140 | } 141 | 142 | 143 | template 144 | THERON_FORCEINLINE EntryType &Directory::GetEntry(const uint32_t index) 145 | { 146 | // Compute the page and offset. 147 | // TODO: Use a mask? 148 | const uint32_t page(index / ENTRIES_PER_PAGE); 149 | const uint32_t offset(index % ENTRIES_PER_PAGE); 150 | 151 | THERON_ASSERT(page < MAX_PAGES); 152 | THERON_ASSERT(offset < ENTRIES_PER_PAGE); 153 | THERON_ASSERT(mPages[page]); 154 | 155 | return mPages[page]->mEntries[offset]; 156 | } 157 | 158 | 159 | } // namespace Detail 160 | } // namespace Theron 161 | 162 | 163 | #endif // THERON_DETAIL_DIRECTORY_DIRECTORY_H 164 | 165 | -------------------------------------------------------------------------------- /Include/Theron/Detail/Directory/Entry.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) by Ashton Mason. See LICENSE.txt for licensing information. 2 | #ifndef THERON_DETAIL_DIRECTORY_ENTRY_H 3 | #define THERON_DETAIL_DIRECTORY_ENTRY_H 4 | 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | #include 11 | 12 | 13 | namespace Theron 14 | { 15 | namespace Detail 16 | { 17 | 18 | 19 | /** 20 | An entry in the directory, potentially recording the registration of one entity. 21 | */ 22 | class Entry 23 | { 24 | public: 25 | 26 | /** 27 | A non-copyable entity that can be registered in a directory. 28 | In order to be registered in the directory, types must derive from this class. 29 | */ 30 | class Entity 31 | { 32 | public: 33 | 34 | /** 35 | \brief Default constructor. 36 | */ 37 | inline Entity() 38 | { 39 | } 40 | 41 | private: 42 | 43 | Entity(const Entity &other); 44 | Entity &operator=(const Entity &other); 45 | }; 46 | 47 | /** 48 | Default constructor. 49 | */ 50 | inline Entry() : 51 | mSpinLock(), 52 | mEntity(0), 53 | mPinCount(0) 54 | { 55 | } 56 | 57 | /** 58 | Lock the entry, acquiring exclusive access. 59 | */ 60 | inline void Lock() const; 61 | 62 | /** 63 | Unlock the entry, relinquishing exclusive access. 64 | */ 65 | inline void Unlock() const; 66 | 67 | /** 68 | Deregisters any entity registered at this entry. 69 | */ 70 | inline void Free(); 71 | 72 | /** 73 | Registers the given entity at this entry. 74 | */ 75 | inline void SetEntity(Entity *const entity); 76 | 77 | /** 78 | Returns a pointer to the entity registered at this entry. 79 | \return A pointer to the registered entity, or zero if no entity is registered. 80 | */ 81 | inline Entity *GetEntity() const; 82 | 83 | /** 84 | Pins the entry, preventing the registered entry from being changed. 85 | */ 86 | inline void Pin(); 87 | 88 | /** 89 | Unpins the entry, allowed the registered entry to be changed. 90 | */ 91 | inline void Unpin(); 92 | 93 | /** 94 | Returns true if the entry has been pinned more times than unpinned. 95 | */ 96 | inline bool IsPinned() const; 97 | 98 | private: 99 | 100 | Entry(const Entry &other); 101 | Entry &operator=(const Entry &other); 102 | 103 | mutable SpinLock mSpinLock; ///< Thread synchronization object protecting the entry. 104 | Entity *mEntity; ///< Pointer to the registered entity. 105 | uint32_t mPinCount; ///< Number of times this entity has been pinned and not unpinned. 106 | }; 107 | 108 | 109 | THERON_FORCEINLINE void Entry::Lock() const 110 | { 111 | mSpinLock.Lock(); 112 | } 113 | 114 | 115 | THERON_FORCEINLINE void Entry::Unlock() const 116 | { 117 | mSpinLock.Unlock(); 118 | } 119 | 120 | 121 | THERON_FORCEINLINE void Entry::Free() 122 | { 123 | THERON_ASSERT(mPinCount == 0); 124 | mEntity = 0; 125 | } 126 | 127 | 128 | THERON_FORCEINLINE void Entry::SetEntity(Entity *const entity) 129 | { 130 | THERON_ASSERT(mPinCount == 0); 131 | mEntity = entity; 132 | } 133 | 134 | 135 | THERON_FORCEINLINE Entry::Entity *Entry::GetEntity() const 136 | { 137 | return mEntity; 138 | } 139 | 140 | 141 | THERON_FORCEINLINE void Entry::Pin() 142 | { 143 | ++mPinCount; 144 | } 145 | 146 | 147 | THERON_FORCEINLINE void Entry::Unpin() 148 | { 149 | THERON_ASSERT(mPinCount > 0); 150 | --mPinCount; 151 | } 152 | 153 | 154 | THERON_FORCEINLINE bool Entry::IsPinned() const 155 | { 156 | return (mPinCount > 0); 157 | } 158 | 159 | 160 | } // namespace Detail 161 | } // namespace Theron 162 | 163 | 164 | #endif // THERON_DETAIL_DIRECTORY_ENTRY_H 165 | 166 | -------------------------------------------------------------------------------- /Include/Theron/Detail/Directory/StaticDirectory.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) by Ashton Mason. See LICENSE.txt for licensing information. 2 | #ifndef THERON_DETAIL_DIRECTORY_STATICDIRECTORY_H 3 | #define THERON_DETAIL_DIRECTORY_STATICDIRECTORY_H 4 | 5 | 6 | #include 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | #include 15 | #include 16 | #include 17 | 18 | 19 | namespace Theron 20 | { 21 | namespace Detail 22 | { 23 | 24 | 25 | /** 26 | Static class template that manages a reference-counted directory singleton. 27 | */ 28 | template 29 | class StaticDirectory 30 | { 31 | public: 32 | 33 | /** 34 | Registers an entity and returns its allocated index. 35 | */ 36 | inline static uint32_t Register(Entry::Entity *const entity); 37 | 38 | /** 39 | Deregisters a previously registered entity. 40 | */ 41 | inline static void Deregister(const uint32_t index); 42 | 43 | /** 44 | Gets a reference to the entry with the given index. 45 | The entry contains data about the entity (if any) registered at the index. 46 | */ 47 | inline static Entry &GetEntry(const uint32_t index); 48 | 49 | private: 50 | 51 | typedef Directory DirectoryType; 52 | 53 | static DirectoryType *smDirectory; ///< Pointer to the allocated instance. 54 | static Mutex smMutex; ///< Synchronization object protecting access. 55 | static uint32_t smReferenceCount; ///< Counts the number of entities registered. 56 | }; 57 | 58 | 59 | template 60 | typename StaticDirectory::DirectoryType *StaticDirectory::smDirectory = 0; 61 | 62 | template 63 | Mutex StaticDirectory::smMutex; 64 | 65 | template 66 | uint32_t StaticDirectory::smReferenceCount = 0; 67 | 68 | 69 | template 70 | inline uint32_t StaticDirectory::Register(Entry::Entity *const entity) 71 | { 72 | smMutex.Lock(); 73 | 74 | // Create the singleton instance if this is the first reference. 75 | if (smReferenceCount++ == 0) 76 | { 77 | IAllocator *const allocator(AllocatorManager::GetCache()); 78 | void *const memory(allocator->AllocateAligned(sizeof(DirectoryType), THERON_CACHELINE_ALIGNMENT)); 79 | 80 | if (memory == 0) 81 | { 82 | return 0; 83 | } 84 | 85 | smDirectory = new (memory) DirectoryType(); 86 | } 87 | 88 | THERON_ASSERT(smDirectory); 89 | 90 | const uint32_t index(smDirectory->Allocate()); 91 | 92 | // Set up the entry. 93 | if (index) 94 | { 95 | Entry &entry(smDirectory->GetEntry(index)); 96 | entry.Lock(); 97 | entry.SetEntity(entity); 98 | entry.Unlock(); 99 | } 100 | 101 | smMutex.Unlock(); 102 | 103 | return index; 104 | } 105 | 106 | 107 | template 108 | inline void StaticDirectory::Deregister(const uint32_t index) 109 | { 110 | smMutex.Lock(); 111 | 112 | THERON_ASSERT(smDirectory); 113 | THERON_ASSERT(index); 114 | 115 | // Clear the entry. 116 | // If the entry is pinned then we have to wait for it to be unpinned. 117 | Entry &entry(smDirectory->GetEntry(index)); 118 | 119 | bool deregistered(false); 120 | while (!deregistered) 121 | { 122 | entry.Lock(); 123 | 124 | if (!entry.IsPinned()) 125 | { 126 | entry.Free(); 127 | deregistered = true; 128 | } 129 | 130 | entry.Unlock(); 131 | } 132 | 133 | // Destroy the singleton instance if this was the last reference. 134 | if (--smReferenceCount == 0) 135 | { 136 | IAllocator *const allocator(AllocatorManager::GetCache()); 137 | smDirectory->~DirectoryType(); 138 | allocator->Free(smDirectory, sizeof(DirectoryType)); 139 | } 140 | 141 | smMutex.Unlock(); 142 | } 143 | 144 | 145 | template 146 | THERON_FORCEINLINE Entry &StaticDirectory::GetEntry(const uint32_t index) 147 | { 148 | THERON_ASSERT(smDirectory); 149 | THERON_ASSERT(index); 150 | 151 | return smDirectory->GetEntry(index); 152 | } 153 | 154 | 155 | } // namespace Detail 156 | } // namespace Theron 157 | 158 | 159 | #endif // THERON_DETAIL_DIRECTORY_STATICDIRECTORY_H 160 | 161 | -------------------------------------------------------------------------------- /Include/Theron/Detail/Handlers/BlindDefaultHandler.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) by Ashton Mason. See LICENSE.txt for licensing information. 2 | #ifndef THERON_DETAIL_HANDLERS_BLINDDEFAULTHANDLER_H 3 | #define THERON_DETAIL_HANDLERS_BLINDDEFAULTHANDLER_H 4 | 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include 12 | #include 13 | #include 14 | 15 | 16 | namespace Theron 17 | { 18 | 19 | 20 | class Actor; 21 | 22 | 23 | namespace Detail 24 | { 25 | 26 | 27 | /** 28 | Instantiable class template that remembers a 'blind' default handler function. 29 | A blind handler is one that takes the message as blind data: a void pointer and a size. 30 | */ 31 | template 32 | class BlindDefaultHandler : public IDefaultHandler 33 | { 34 | public: 35 | 36 | /** 37 | Pointer to a member function of the actor type, which is the handler. 38 | */ 39 | typedef void (ActorType::*HandlerFunction)(const void *const data, const uint32_t size, const Address from); 40 | 41 | /** 42 | Constructor. 43 | */ 44 | THERON_FORCEINLINE explicit BlindDefaultHandler(HandlerFunction function) : mHandlerFunction(function) 45 | { 46 | } 47 | 48 | /** 49 | Virtual destructor. 50 | */ 51 | inline virtual ~BlindDefaultHandler() 52 | { 53 | } 54 | 55 | /** 56 | Handles the given message. 57 | \note The message is not consumed by the handler; just acted on or ignored. 58 | The message will be automatically destroyed when all handlers have seen it. 59 | */ 60 | inline virtual void Handle(Actor *const actor, const IMessage *const message) const; 61 | 62 | private: 63 | 64 | BlindDefaultHandler(const BlindDefaultHandler &other); 65 | BlindDefaultHandler &operator=(const BlindDefaultHandler &other); 66 | 67 | const HandlerFunction mHandlerFunction; ///< Pointer to a handler member function on the actor. 68 | }; 69 | 70 | 71 | template 72 | inline void BlindDefaultHandler::Handle(Actor *const actor, const IMessage *const message) const 73 | { 74 | THERON_ASSERT(actor); 75 | THERON_ASSERT(message); 76 | THERON_ASSERT(mHandlerFunction); 77 | 78 | // Call the handler, passing it the from address and also the message as blind data. 79 | ActorType *const typedActor = static_cast(actor); 80 | 81 | const void *const messageData(message->GetMessageData()); 82 | const uint32_t messageSize(message->GetMessageSize()); 83 | const Theron::Address from(message->From()); 84 | 85 | THERON_ASSERT(messageData && messageSize); 86 | 87 | (typedActor->*mHandlerFunction)(messageData, messageSize, from); 88 | } 89 | 90 | 91 | } // namespace Detail 92 | } // namespace Theron 93 | 94 | 95 | #endif // THERON_DETAIL_HANDLERS_BLINDDEFAULTHANDLER_H 96 | -------------------------------------------------------------------------------- /Include/Theron/Detail/Handlers/BlindFallbackHandler.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) by Ashton Mason. See LICENSE.txt for licensing information. 2 | #ifndef THERON_DETAIL_HANDLERS_BLINDFALLBACKHANDLER_H 3 | #define THERON_DETAIL_HANDLERS_BLINDFALLBACKHANDLER_H 4 | 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include 12 | #include 13 | 14 | 15 | namespace Theron 16 | { 17 | namespace Detail 18 | { 19 | 20 | 21 | /** 22 | Instantiable class template that remembers a 'blind' fallback message handler function 23 | registered with a framework and called for messages that are undelivered or unhandled. 24 | A blind handler is one that takes the message as blind data: a void pointer and a size. 25 | \tparam ObjectType The class on which the handler function is a method. 26 | */ 27 | template 28 | class BlindFallbackHandler : public IFallbackHandler 29 | { 30 | public: 31 | 32 | /** 33 | Pointer to a member function of a handler object. 34 | */ 35 | typedef void (ObjectType::*HandlerFunction)(const void *const data, const uint32_t size, const Address from); 36 | 37 | /** 38 | Constructor. 39 | */ 40 | THERON_FORCEINLINE BlindFallbackHandler(ObjectType *const object, HandlerFunction function) : 41 | mObject(object), 42 | mHandlerFunction(function) 43 | { 44 | } 45 | 46 | /** 47 | Virtual destructor. 48 | */ 49 | inline virtual ~BlindFallbackHandler() 50 | { 51 | } 52 | 53 | /** 54 | Handles the given message. 55 | */ 56 | inline virtual void Handle(const IMessage *const message) const 57 | { 58 | THERON_ASSERT(mObject); 59 | THERON_ASSERT(mHandlerFunction); 60 | THERON_ASSERT(message); 61 | 62 | // Call the handler, passing it the from address and also the message as blind data. 63 | const void *const messageData(message->GetMessageData()); 64 | const uint32_t messageSize(message->GetMessageSize()); 65 | const Theron::Address from(message->From()); 66 | 67 | THERON_ASSERT(messageData && messageSize); 68 | 69 | (mObject->*mHandlerFunction)(messageData, messageSize, from); 70 | } 71 | 72 | private: 73 | 74 | BlindFallbackHandler(const BlindFallbackHandler &other); 75 | BlindFallbackHandler &operator=(const BlindFallbackHandler &other); 76 | 77 | ObjectType *mObject; ///< Pointer to the object owning the handler function. 78 | const HandlerFunction mHandlerFunction; ///< Pointer to the handler member function on the owning object. 79 | }; 80 | 81 | 82 | } // namespace Detail 83 | } // namespace Theron 84 | 85 | 86 | #endif // THERON_DETAIL_HANDLERS_BLINDFALLBACKHANDLER_H 87 | -------------------------------------------------------------------------------- /Include/Theron/Detail/Handlers/DefaultFallbackHandler.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) by Ashton Mason. See LICENSE.txt for licensing information. 2 | #ifndef THERON_DETAIL_HANDLERS_DEFAULTFALLBACKHANDLER_H 3 | #define THERON_DETAIL_HANDLERS_DEFAULTFALLBACKHANDLER_H 4 | 5 | 6 | #if THERON_ENABLE_UNHANDLED_MESSAGE_CHECKS 7 | #include 8 | #endif // THERON_ENABLE_UNHANDLED_MESSAGE_CHECKS 9 | 10 | #include 11 | #include 12 | #include 13 | 14 | 15 | #if THERON_ENABLE_UNHANDLED_MESSAGE_CHECKS 16 | #define THERON_FALLBACK_HANDLER_ARG(x) x 17 | #else 18 | #define THERON_FALLBACK_HANDLER_ARG(x) 19 | #endif //THERON_ENABLE_UNHANDLED_MESSAGE_CHECKS 20 | 21 | 22 | namespace Theron 23 | { 24 | namespace Detail 25 | { 26 | 27 | 28 | class DefaultFallbackHandler 29 | { 30 | public: 31 | 32 | inline void Handle(const void *const data, const uint32_t size, const Address from); 33 | }; 34 | 35 | 36 | inline void DefaultFallbackHandler::Handle( 37 | const void *const THERON_FALLBACK_HANDLER_ARG(data), 38 | const uint32_t THERON_FALLBACK_HANDLER_ARG(size), 39 | const Address THERON_FALLBACK_HANDLER_ARG(from)) 40 | { 41 | #if THERON_ENABLE_UNHANDLED_MESSAGE_CHECKS 42 | 43 | fprintf(stderr, "Unhandled message of %d bytes sent from address %d:\n", size, from.AsInteger()); 44 | 45 | // Dump the message data as hex words. 46 | if (data) 47 | { 48 | const char *const format("[%d] 0x%08x\n"); 49 | 50 | const unsigned int *const begin(reinterpret_cast(data)); 51 | const unsigned int *const end(begin + size / sizeof(unsigned int)); 52 | 53 | for (const unsigned int *word(begin); word != end; ++word) 54 | { 55 | fprintf(stderr, format, static_cast(word - begin), static_cast(*word)); 56 | } 57 | } 58 | 59 | THERON_FAIL(); 60 | 61 | #endif // THERON_ENABLE_UNHANDLED_MESSAGE_CHECKS 62 | } 63 | 64 | 65 | } // namespace Detail 66 | } // namespace Theron 67 | 68 | 69 | #undef THERON_FALLBACK_HANDLER_ARG 70 | 71 | 72 | #endif // THERON_DETAIL_HANDLERS_DEFAULTFALLBACKHANDLER_H 73 | -------------------------------------------------------------------------------- /Include/Theron/Detail/Handlers/DefaultHandler.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) by Ashton Mason. See LICENSE.txt for licensing information. 2 | #ifndef THERON_DETAIL_HANDLERS_DEFAULTHANDLER_H 3 | #define THERON_DETAIL_HANDLERS_DEFAULTHANDLER_H 4 | 5 | 6 | #include 7 | #include 8 | 9 | #include 10 | #include 11 | #include 12 | 13 | 14 | namespace Theron 15 | { 16 | 17 | 18 | class Actor; 19 | 20 | 21 | namespace Detail 22 | { 23 | 24 | 25 | /** 26 | Instantiable class template that remembers a default handler function. 27 | */ 28 | template 29 | class DefaultHandler : public IDefaultHandler 30 | { 31 | public: 32 | 33 | /** 34 | Pointer to a member function of the actor type, which is the handler. 35 | */ 36 | typedef void (ActorType::*HandlerFunction)(const Address from); 37 | 38 | /** 39 | Constructor. 40 | */ 41 | THERON_FORCEINLINE explicit DefaultHandler(HandlerFunction function) : mHandlerFunction(function) 42 | { 43 | } 44 | 45 | /** 46 | Virtual destructor. 47 | */ 48 | inline virtual ~DefaultHandler() 49 | { 50 | } 51 | 52 | /** 53 | Handles the given message. 54 | \note The message is not consumed by the handler; just acted on or ignored. 55 | The message will be automatically destroyed when all handlers have seen it. 56 | */ 57 | inline virtual void Handle(Actor *const actor, const IMessage *const message) const; 58 | 59 | private: 60 | 61 | DefaultHandler(const DefaultHandler &other); 62 | DefaultHandler &operator=(const DefaultHandler &other); 63 | 64 | const HandlerFunction mHandlerFunction; ///< Pointer to a handler member function on the actor. 65 | }; 66 | 67 | 68 | template 69 | inline void DefaultHandler::Handle(Actor *const actor, const IMessage *const message) const 70 | { 71 | THERON_ASSERT(actor); 72 | THERON_ASSERT(message); 73 | THERON_ASSERT(mHandlerFunction); 74 | 75 | // Call the handler, passing it the from address. 76 | // We can't pass the value because we don't even know the type. 77 | ActorType *const typedActor = static_cast(actor); 78 | (typedActor->*mHandlerFunction)(message->From()); 79 | } 80 | 81 | 82 | } // namespace Detail 83 | } // namespace Theron 84 | 85 | 86 | #endif // THERON_DETAIL_HANDLERS_DEFAULTHANDLER_H 87 | -------------------------------------------------------------------------------- /Include/Theron/Detail/Handlers/FallbackHandler.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) by Ashton Mason. See LICENSE.txt for licensing information. 2 | #ifndef THERON_DETAIL_HANDLERS_FALLBACKHANDLER_H 3 | #define THERON_DETAIL_HANDLERS_FALLBACKHANDLER_H 4 | 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | #include 11 | #include 12 | 13 | 14 | namespace Theron 15 | { 16 | namespace Detail 17 | { 18 | 19 | 20 | /** 21 | Instantiable class template that remembers a fallback message handler function 22 | registered with a framework and called for messages that are undelivered or unhandled. 23 | \tparam ObjectType The class on which the handler function is a method. 24 | */ 25 | template 26 | class FallbackHandler : public IFallbackHandler 27 | { 28 | public: 29 | 30 | /** 31 | Pointer to a member function of a handler object. 32 | */ 33 | typedef void (ObjectType::*HandlerFunction)(const Address from); 34 | 35 | /** 36 | Constructor. 37 | */ 38 | THERON_FORCEINLINE FallbackHandler(ObjectType *const object, HandlerFunction function) : 39 | mObject(object), 40 | mHandlerFunction(function) 41 | { 42 | } 43 | 44 | /** 45 | Virtual destructor. 46 | */ 47 | inline virtual ~FallbackHandler() 48 | { 49 | } 50 | 51 | /** 52 | Handles the given message. 53 | */ 54 | inline virtual void Handle(const IMessage *const message) const 55 | { 56 | THERON_ASSERT(mObject); 57 | THERON_ASSERT(mHandlerFunction); 58 | THERON_ASSERT(message); 59 | 60 | // Call the handler, passing it the from address. 61 | (mObject->*mHandlerFunction)(message->From()); 62 | } 63 | 64 | private: 65 | 66 | FallbackHandler(const FallbackHandler &other); 67 | FallbackHandler &operator=(const FallbackHandler &other); 68 | 69 | ObjectType *mObject; ///< Pointer to the object owning the handler function. 70 | const HandlerFunction mHandlerFunction; ///< Pointer to the handler member function on the owning object. 71 | }; 72 | 73 | 74 | } // namespace Detail 75 | } // namespace Theron 76 | 77 | 78 | #endif // THERON_DETAIL_HANDLERS_FALLBACKHANDLER_H 79 | -------------------------------------------------------------------------------- /Include/Theron/Detail/Handlers/IDefaultHandler.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) by Ashton Mason. See LICENSE.txt for licensing information. 2 | #ifndef THERON_DETAIL_HANDLERS_IDEFAULTHANDLER_H 3 | #define THERON_DETAIL_HANDLERS_IDEFAULTHANDLER_H 4 | 5 | 6 | #include 7 | #include 8 | 9 | #include 10 | 11 | 12 | namespace Theron 13 | { 14 | 15 | 16 | class Actor; 17 | 18 | 19 | namespace Detail 20 | { 21 | 22 | 23 | /** 24 | Baseclass that allows default handlers to be stored in lists. 25 | */ 26 | class IDefaultHandler 27 | { 28 | public: 29 | 30 | /** 31 | Default constructor. 32 | */ 33 | inline IDefaultHandler() 34 | { 35 | } 36 | 37 | /** 38 | Virtual destructor. 39 | */ 40 | inline virtual ~IDefaultHandler() 41 | { 42 | } 43 | 44 | /** 45 | Handles the given message. 46 | */ 47 | virtual void Handle(Actor *const actor, const IMessage *const message) const = 0; 48 | 49 | private: 50 | 51 | IDefaultHandler(const IDefaultHandler &other); 52 | IDefaultHandler &operator=(const IDefaultHandler &other); 53 | }; 54 | 55 | 56 | } // namespace Detail 57 | } // namespace Theron 58 | 59 | 60 | #endif // THERON_DETAIL_HANDLERS_IDEFAULTHANDLER_H 61 | -------------------------------------------------------------------------------- /Include/Theron/Detail/Handlers/IFallbackHandler.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) by Ashton Mason. See LICENSE.txt for licensing information. 2 | #ifndef THERON_DETAIL_HANDLERS_IFALLBACKHANDLER_H 3 | #define THERON_DETAIL_HANDLERS_IFALLBACKHANDLER_H 4 | 5 | 6 | #include 7 | #include 8 | 9 | #include 10 | #include 11 | 12 | 13 | namespace Theron 14 | { 15 | namespace Detail 16 | { 17 | 18 | 19 | /** 20 | Baseclass that allows fallback handlers to be stored in lists. 21 | */ 22 | class IFallbackHandler : public List::Node 23 | { 24 | public: 25 | 26 | /** 27 | Default constructor. 28 | */ 29 | THERON_FORCEINLINE IFallbackHandler() 30 | { 31 | } 32 | 33 | /** 34 | Virtual destructor. 35 | */ 36 | inline virtual ~IFallbackHandler() 37 | { 38 | } 39 | 40 | /** 41 | Handles the given message. 42 | */ 43 | virtual void Handle(const IMessage *const message) const = 0; 44 | 45 | private: 46 | 47 | IFallbackHandler(const IFallbackHandler &other); 48 | IFallbackHandler &operator=(const IFallbackHandler &other); 49 | }; 50 | 51 | 52 | } // namespace Detail 53 | } // namespace Theron 54 | 55 | 56 | #endif // THERON_DETAIL_HANDLERS_IFALLBACKHANDLER_H 57 | 58 | -------------------------------------------------------------------------------- /Include/Theron/Detail/Handlers/IMessageHandler.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) by Ashton Mason. See LICENSE.txt for licensing information. 2 | #ifndef THERON_DETAIL_HANDLERS_IMESSAGEHANDLER_H 3 | #define THERON_DETAIL_HANDLERS_IMESSAGEHANDLER_H 4 | 5 | 6 | #include 7 | #include 8 | 9 | #include 10 | #include 11 | 12 | 13 | namespace Theron 14 | { 15 | 16 | 17 | class Actor; 18 | 19 | 20 | namespace Detail 21 | { 22 | 23 | 24 | /** 25 | Baseclass that allows message handlers of various types to be stored in lists. 26 | */ 27 | class IMessageHandler : public List::Node 28 | { 29 | public: 30 | 31 | /** 32 | Default constructor. 33 | */ 34 | THERON_FORCEINLINE IMessageHandler() : mMarked(false), mPredictedSendCount(0) 35 | { 36 | } 37 | 38 | /** 39 | Virtual destructor. 40 | */ 41 | inline virtual ~IMessageHandler() 42 | { 43 | } 44 | 45 | /** 46 | Marks the handler (eg. for deletion). 47 | */ 48 | inline void Mark(); 49 | 50 | /** 51 | Returns true if the handler is marked (eg. for deletion). 52 | */ 53 | inline bool IsMarked() const; 54 | 55 | /** 56 | Reports the number of messages sent by an invocation of the handler. 57 | */ 58 | inline void ReportSendCount(const uint32_t count); 59 | 60 | /** 61 | Gets a prediction of the number of messages that would be sent by the handler when invoked. 62 | */ 63 | inline uint32_t GetPredictedSendCount() const; 64 | 65 | /** 66 | Returns the unique name of the message type handled by this handler. 67 | */ 68 | virtual const char *GetMessageTypeName() const = 0; 69 | 70 | /** 71 | Handles the given message, if it's of the type accepted by the handler. 72 | \return True, if the handler handled the message. 73 | */ 74 | virtual bool Handle(Actor *const actor, const IMessage *const message) = 0; 75 | 76 | private: 77 | 78 | IMessageHandler(const IMessageHandler &other); 79 | IMessageHandler &operator=(const IMessageHandler &other); 80 | 81 | bool mMarked; ///< Flag used to mark the handler for deletion. 82 | uint32_t mPredictedSendCount; ///< Number of messages that are predicted to be sent by the handler. 83 | }; 84 | 85 | 86 | THERON_FORCEINLINE void IMessageHandler::Mark() 87 | { 88 | mMarked = true; 89 | } 90 | 91 | 92 | THERON_FORCEINLINE bool IMessageHandler::IsMarked() const 93 | { 94 | return mMarked; 95 | } 96 | 97 | 98 | THERON_FORCEINLINE void IMessageHandler::ReportSendCount(const uint32_t count) 99 | { 100 | // For now we assume that the message send count will be the same as last time. 101 | if (mPredictedSendCount != count) 102 | { 103 | mPredictedSendCount = count; 104 | } 105 | } 106 | 107 | 108 | THERON_FORCEINLINE uint32_t IMessageHandler::GetPredictedSendCount() const 109 | { 110 | return mPredictedSendCount; 111 | } 112 | 113 | 114 | } // namespace Detail 115 | } // namespace Theron 116 | 117 | 118 | #endif // THERON_DETAIL_HANDLERS_IMESSAGEHANDLER_H 119 | -------------------------------------------------------------------------------- /Include/Theron/Detail/Handlers/IReceiverHandler.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) by Ashton Mason. See LICENSE.txt for licensing information. 2 | #ifndef THERON_DETAIL_HANDLERS_IRECEIVERHANDLER_H 3 | #define THERON_DETAIL_HANDLERS_IRECEIVERHANDLER_H 4 | 5 | 6 | #include 7 | #include 8 | 9 | #include 10 | #include 11 | 12 | 13 | namespace Theron 14 | { 15 | namespace Detail 16 | { 17 | 18 | 19 | /** 20 | Baseclass that allows message handlers of various types to be stored in lists. 21 | */ 22 | class IReceiverHandler : public List::Node 23 | { 24 | public: 25 | 26 | /** 27 | Default constructor. 28 | */ 29 | THERON_FORCEINLINE IReceiverHandler() 30 | { 31 | } 32 | 33 | /** 34 | Virtual destructor. 35 | */ 36 | inline virtual ~IReceiverHandler() 37 | { 38 | } 39 | 40 | /** 41 | Returns the unique name of the message type handled by this handler. 42 | */ 43 | virtual const char *GetMessageTypeName() const = 0; 44 | 45 | /** 46 | Handles the given message, if it's of the type accepted by the handler. 47 | \return True, if the handler handled the message. 48 | */ 49 | virtual bool Handle(const IMessage *const message) const = 0; 50 | 51 | private: 52 | 53 | IReceiverHandler(const IReceiverHandler &other); 54 | IReceiverHandler &operator=(const IReceiverHandler &other); 55 | }; 56 | 57 | 58 | } // namespace Detail 59 | } // namespace Theron 60 | 61 | 62 | #endif // THERON_DETAIL_HANDLERS_IRECEIVERHANDLER_H 63 | -------------------------------------------------------------------------------- /Include/Theron/Detail/Handlers/MessageHandler.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) by Ashton Mason. See LICENSE.txt for licensing information. 2 | #ifndef THERON_DETAIL_HANDLERS_MESSAGEHANDLER_H 3 | #define THERON_DETAIL_HANDLERS_MESSAGEHANDLER_H 4 | 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | 17 | namespace Theron 18 | { 19 | 20 | 21 | class Actor; 22 | 23 | 24 | namespace Detail 25 | { 26 | 27 | 28 | /** 29 | Instantiable class template that remembers a message handler function and 30 | the type of message it accepts. It is responsible for checking whether 31 | incoming messages are of the type accepted by the handler, and executing the 32 | handler for messages that match. 33 | 34 | Incoming messages are cast at runtime to the type of message handled by the 35 | stored handler, and the handler is executed only if the cast succeeds (returns 36 | a non-zero pointer). The dynamic cast operation is specialized to use either 37 | C++ dynamic_cast or a hand-rolled runtime type information (RTTI) system 38 | that avoids introducing the type information into types other than messages. 39 | 40 | \tparam ActorType The type of actor whose message handlers are considered. 41 | \tparam ValueType The type of message handled by this message handler. 42 | */ 43 | template 44 | class MessageHandler : public IMessageHandler 45 | { 46 | public: 47 | 48 | /** 49 | Pointer to a member function of the actor type that can handle messages 50 | with the given value type. 51 | */ 52 | typedef void (ActorType::*HandlerFunction)(const ValueType &message, const Address from); 53 | 54 | /** 55 | Constructor. 56 | */ 57 | inline explicit MessageHandler(HandlerFunction function) : mHandlerFunction(function) 58 | { 59 | } 60 | 61 | /** 62 | Virtual destructor. 63 | */ 64 | inline virtual ~MessageHandler() 65 | { 66 | } 67 | 68 | /** 69 | Returns a pointer to the handler function registered by this instance. 70 | */ 71 | THERON_FORCEINLINE HandlerFunction GetHandlerFunction() const 72 | { 73 | return mHandlerFunction; 74 | } 75 | 76 | /** 77 | Returns the unique name of the message type handled by this handler. 78 | */ 79 | inline virtual const char *GetMessageTypeName() const 80 | { 81 | return MessageTraits::TYPE_NAME; 82 | } 83 | 84 | /** 85 | Handles the given message, if it's of the type accepted by the handler. 86 | \return True, if the handler handled the message. 87 | \note The message is not consumed by the handler; just acted on or ignored. 88 | The message will be automatically destroyed when all handlers have seen it. 89 | */ 90 | inline virtual bool Handle(Actor *const actor, const IMessage *const message) 91 | { 92 | typedef MessageCast::HAS_TYPE_NAME> MessageCaster; 93 | 94 | THERON_ASSERT(actor); 95 | THERON_ASSERT(mHandlerFunction); 96 | THERON_ASSERT(message); 97 | 98 | // Try to convert the message, of unknown type, to message of the assumed type. 99 | const Message *const typedMessage = MessageCaster:: template CastMessage(message); 100 | if (typedMessage) 101 | { 102 | // Call the handler, passing it the message value and from address. 103 | ActorType *const typedActor = static_cast(actor); 104 | (typedActor->*mHandlerFunction)(typedMessage->Value(), typedMessage->From()); 105 | 106 | return true; 107 | } 108 | 109 | return false; 110 | } 111 | 112 | private: 113 | 114 | MessageHandler(const MessageHandler &other); 115 | MessageHandler &operator=(const MessageHandler &other); 116 | 117 | const HandlerFunction mHandlerFunction; ///< Pointer to a handler member function on an actor. 118 | }; 119 | 120 | 121 | } // namespace Detail 122 | } // namespace Theron 123 | 124 | 125 | #endif // THERON_DETAIL_HANDLERS_MESSAGEHANDLER_H 126 | -------------------------------------------------------------------------------- /Include/Theron/Detail/Handlers/MessageHandlerCast.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) by Ashton Mason. See LICENSE.txt for licensing information. 2 | #ifndef THERON_DETAIL_HANDLERS_MESSAGEHANDLERCAST_H 3 | #define THERON_DETAIL_HANDLERS_MESSAGEHANDLERCAST_H 4 | 5 | 6 | #include 7 | #include 8 | 9 | #include 10 | #include 11 | #include 12 | 13 | 14 | namespace Theron 15 | { 16 | namespace Detail 17 | { 18 | 19 | 20 | /** 21 | \brief Dynamic cast utility for message handler pointers. 22 | A cast utility that can be used to dynamically cast a message handler of unknown type 23 | to a message handler of a known type at runtime, using stored runtime type information. 24 | If the unknown message handler is of the target type then the cast succeeds and a pointer 25 | to the typecast message handler is returned, otherwise a null pointer is returned. 26 | 27 | This utility roughly mimics the functionality of dynamic_cast, but includes 28 | two alternate implementations: one that uses dynamic_cast directly and another 29 | that rolls its own runtime type information only for message handler classes. The 30 | advantage of the second implementation is that the storage overhead of the extra 31 | runtime type information is not imposed on \em all classes, as with the C++ RTTI. 32 | If the second implementation is used consistently then dynamic_cast is not 33 | called at all, using a partial template specialization trick, and the C++ RTTI 34 | functionality can be turned off (usually by means of a compiler option). 35 | 36 | \note Partial template specialization is used here as a device to avoid 37 | introducing a hardcoded dependency on C++ RTTI. The dependency can be avoided 38 | by defining non-zero type names for all message types used in the application. 39 | 40 | \tparam ActorType The actor class for which the handler is registered. 41 | \tparam HAS_TYPE_NAME A flag indicating whether the message type has a name. 42 | */ 43 | template 44 | class MessageHandlerCast 45 | { 46 | public: 47 | 48 | /** 49 | \brief Attempts to convert a given message handler, of unknown type, to one of a target type. 50 | Returns a null pointer if the message handler is of the wrong type. 51 | \tparam ValueType The value type of the target message handler. 52 | \param handler A pointer to the message handler of unknown type. 53 | \return A pointer to the converted message handler, or null if the types don't match. 54 | */ 55 | template 56 | THERON_FORCEINLINE static const MessageHandler *CastHandler(const IMessageHandler *const handler) 57 | { 58 | THERON_ASSERT(handler); 59 | 60 | // If explicit type names are used then they must be defined for all message types. 61 | THERON_ASSERT_MSG(handler->GetMessageTypeName(), "Missing type name for message type"); 62 | 63 | // Compare the handlers using type names. 64 | if (handler->GetMessageTypeName() != MessageTraits::TYPE_NAME) 65 | { 66 | return 0; 67 | } 68 | 69 | // Convert the given message handler to a handler for the known type. 70 | typedef MessageHandler HandlerType; 71 | return reinterpret_cast(handler); 72 | } 73 | }; 74 | 75 | 76 | // Specialization of the MessageHandlerCast for the case where the message type has no type name. 77 | // This specialization uses C++ built-in RTTI instead of explicitly stored type names. 78 | template 79 | class MessageHandlerCast 80 | { 81 | public: 82 | 83 | /** 84 | Attempts to convert the given message handler, of unknown message type, to a handler of the given type. 85 | \note Returns a null pointer if the unknown handler is of the wrong type. 86 | */ 87 | template 88 | THERON_FORCEINLINE static const MessageHandler *CastHandler(const IMessageHandler *const handler) 89 | { 90 | THERON_ASSERT(handler); 91 | 92 | // Explicit type names must be defined for all message types or none at all. 93 | THERON_ASSERT_MSG(handler->GetMessageTypeName() == 0, "Type names specified for only some message types!"); 94 | 95 | // Try to convert the given message handler to this type. 96 | typedef MessageHandler HandlerType; 97 | return dynamic_cast(handler); 98 | } 99 | }; 100 | 101 | 102 | } // namespace Detail 103 | } // namespace Theron 104 | 105 | 106 | #endif // THERON_DETAIL_HANDLERS_MESSAGEHANDLERCAST_H 107 | -------------------------------------------------------------------------------- /Include/Theron/Detail/Handlers/ReceiverHandler.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) by Ashton Mason. See LICENSE.txt for licensing information. 2 | #ifndef THERON_DETAIL_HANDLERS_RECEIVERHANDLER_H 3 | #define THERON_DETAIL_HANDLERS_RECEIVERHANDLER_H 4 | 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | 17 | namespace Theron 18 | { 19 | namespace Detail 20 | { 21 | 22 | 23 | /** 24 | Instantiable class template that remembers a message handler function and 25 | the type of message it accepts. It is responsible for checking whether 26 | incoming messages are of the type accepted by the handler, and executing the 27 | handler for messages that match. 28 | 29 | Incoming messages are cast at runtime to the type of message handled by the 30 | stored handler, and the handler is executed only if the cast succeeds (returns 31 | a non-zero pointer). The dynamic cast operation is specialized to use either 32 | C++ dynamic_cast or a hand-rolled runtime type information (RTTI) system 33 | that avoids introducing the type information into types other than messages. 34 | 35 | \tparam ObjectType The class on which the handler function is a method. 36 | \tparam ValueType The type of message handled by the message handler. 37 | */ 38 | template 39 | class ReceiverHandler : public IReceiverHandler 40 | { 41 | public: 42 | 43 | /** 44 | Pointer to a member function of the object type that can handle messages 45 | with the given value type. 46 | */ 47 | typedef void (ObjectType::*HandlerFunction)(const ValueType &message, const Address from); 48 | 49 | /** 50 | Constructor. 51 | */ 52 | inline ReceiverHandler(ObjectType *const object, HandlerFunction function) : 53 | mObject(object), 54 | mHandlerFunction(function) 55 | { 56 | } 57 | 58 | /** 59 | Virtual destructor. 60 | */ 61 | inline virtual ~ReceiverHandler() 62 | { 63 | } 64 | 65 | /** 66 | Returns a pointer to the handler function registered by this instance. 67 | */ 68 | THERON_FORCEINLINE HandlerFunction GetHandlerFunction() const 69 | { 70 | return mHandlerFunction; 71 | } 72 | 73 | /** 74 | Returns the unique name of the message type handled by this handler. 75 | */ 76 | inline virtual const char *GetMessageTypeName() const 77 | { 78 | return MessageTraits::TYPE_NAME; 79 | } 80 | 81 | /** 82 | Handles the given message, if it's of the type accepted by the handler. 83 | \return True, if the handler handled the message. 84 | \note The message is not consumed by the handler; just acted on or ignored. 85 | The message will be automatically destroyed when all handlers have seen it. 86 | */ 87 | inline virtual bool Handle(const IMessage *const message) const 88 | { 89 | typedef MessageCast::HAS_TYPE_NAME> MessageCaster; 90 | 91 | THERON_ASSERT(mObject); 92 | THERON_ASSERT(mHandlerFunction); 93 | THERON_ASSERT(message); 94 | 95 | // Try to convert the message, of unknown type, to message of the assumed type. 96 | const Message *const typedMessage = MessageCaster:: template CastMessage(message); 97 | if (typedMessage) 98 | { 99 | // Call the handler, passing it the message value and from address. 100 | (mObject->*mHandlerFunction)(typedMessage->Value(), typedMessage->From()); 101 | return true; 102 | } 103 | 104 | return false; 105 | } 106 | 107 | private: 108 | 109 | ReceiverHandler(const ReceiverHandler &other); 110 | ReceiverHandler &operator=(const ReceiverHandler &other); 111 | 112 | ObjectType *mObject; ///< Pointer to the object owning the handler function. 113 | const HandlerFunction mHandlerFunction; ///< Pointer to the handler member function on the owning object. 114 | }; 115 | 116 | 117 | } // namespace Detail 118 | } // namespace Theron 119 | 120 | 121 | #endif // THERON_DETAIL_HANDLERS_RECEIVERHANDLER_H 122 | -------------------------------------------------------------------------------- /Include/Theron/Detail/Handlers/ReceiverHandlerCast.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) by Ashton Mason. See LICENSE.txt for licensing information. 2 | #ifndef THERON_DETAIL_HANDLERS_RECEIVERHANDLERCAST_H 3 | #define THERON_DETAIL_HANDLERS_RECEIVERHANDLERCAST_H 4 | 5 | 6 | #include 7 | #include 8 | 9 | #include 10 | #include 11 | #include 12 | 13 | 14 | namespace Theron 15 | { 16 | namespace Detail 17 | { 18 | 19 | 20 | /** 21 | \brief Dynamic cast utility for message handler pointers. 22 | */ 23 | template 24 | class ReceiverHandlerCast 25 | { 26 | public: 27 | 28 | /** 29 | \brief Attempts to convert a given message handler, of unknown type, to one of a target type. 30 | */ 31 | template 32 | THERON_FORCEINLINE static const ReceiverHandler *CastHandler(const IReceiverHandler *const handler) 33 | { 34 | THERON_ASSERT(handler); 35 | 36 | // If explicit type names are used then they must be defined for all message types. 37 | THERON_ASSERT_MSG(handler->GetMessageTypeName(), "Missing type name for message type"); 38 | 39 | // Compare the handlers using type names. 40 | if (handler->GetMessageTypeName() != MessageTraits::TYPE_NAME) 41 | { 42 | return 0; 43 | } 44 | 45 | // Convert the given message handler to a handler for the known type. 46 | typedef ReceiverHandler HandlerType; 47 | return reinterpret_cast(handler); 48 | } 49 | }; 50 | 51 | 52 | // Specialization of the ReceiverHandlerCast for the case where the message type has no type name. 53 | // This specialization uses C++ built-in RTTI instead of explicitly stored type names. 54 | template 55 | class ReceiverHandlerCast 56 | { 57 | public: 58 | 59 | /** 60 | Attempts to convert the given message handler, of unknown message type, to a handler of the given type. 61 | \note Returns a null pointer if the unknown handler is of the wrong type. 62 | */ 63 | template 64 | THERON_FORCEINLINE static const ReceiverHandler *CastHandler(const IReceiverHandler *const handler) 65 | { 66 | THERON_ASSERT(handler); 67 | 68 | // Explicit type names must be defined for all message types or none at all. 69 | THERON_ASSERT_MSG(handler->GetMessageTypeName() == 0, "Type names specified for only some message types!"); 70 | 71 | // Try to convert the given message handler to this type. 72 | typedef ReceiverHandler HandlerType; 73 | return dynamic_cast(handler); 74 | } 75 | }; 76 | 77 | 78 | } // namespace Detail 79 | } // namespace Theron 80 | 81 | 82 | #endif // THERON_DETAIL_HANDLERS_RECEIVERHANDLERCAST_H 83 | -------------------------------------------------------------------------------- /Include/Theron/Detail/Messages/IMessage.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) by Ashton Mason. See LICENSE.txt for licensing information. 2 | #ifndef THERON_DETAIL_MESSAGES_IMESSAGE_H 3 | #define THERON_DETAIL_MESSAGES_IMESSAGE_H 4 | 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include 12 | 13 | 14 | namespace Theron 15 | { 16 | namespace Detail 17 | { 18 | 19 | 20 | /** 21 | Interface describing the generic API of the message class template. 22 | */ 23 | class IMessage : public Queue::Node 24 | { 25 | public: 26 | 27 | /** 28 | Gets the address from which the message was sent. 29 | // TODO: Force-inline 30 | */ 31 | inline Address From() const 32 | { 33 | return mFrom; 34 | } 35 | 36 | /** 37 | Returns the memory block in which this message was allocated. 38 | */ 39 | THERON_FORCEINLINE void *GetBlock() const 40 | { 41 | THERON_ASSERT(mBlock); 42 | return mBlock; 43 | } 44 | 45 | /** 46 | Returns the size in bytes of the memory block in which this message was allocated. 47 | */ 48 | THERON_FORCEINLINE uint32_t GetBlockSize() const 49 | { 50 | THERON_ASSERT(mBlockSize); 51 | return mBlockSize; 52 | } 53 | 54 | /** 55 | Returns the message value as blind data. 56 | */ 57 | THERON_FORCEINLINE const void *GetMessageData() const 58 | { 59 | THERON_ASSERT(mBlock); 60 | return mBlock; 61 | } 62 | 63 | /** 64 | Returns the size in bytes of the message data. 65 | */ 66 | virtual uint32_t GetMessageSize() const = 0; 67 | 68 | /** 69 | Returns the name of the message type. 70 | This uniquely identifies the type of the message value. 71 | \note Unless explicitly specified to avoid C++ RTTI, message names are null. 72 | */ 73 | virtual const char *TypeName() const = 0; 74 | 75 | /** 76 | Allows the message instance to destruct its constructed value object before being freed. 77 | */ 78 | virtual void Release() = 0; 79 | 80 | /** 81 | Virtual destructor. 82 | */ 83 | virtual ~IMessage() 84 | { 85 | } 86 | 87 | protected: 88 | 89 | /** 90 | Constructs an IMessage. 91 | \param from The address from which the message was sent. 92 | \param block The memory block containing the message. 93 | \param blockSize The size of the memory block containing the message. 94 | \param typeName String identifier uniquely identifying the type of the message value. 95 | */ 96 | THERON_FORCEINLINE IMessage( 97 | const Address &from, 98 | void *const block, 99 | const uint32_t blockSize) : 100 | mFrom(from), 101 | mBlock(block), 102 | mBlockSize(blockSize) 103 | { 104 | } 105 | 106 | private: 107 | 108 | IMessage(const IMessage &other); 109 | IMessage &operator=(const IMessage &other); 110 | 111 | const Address mFrom; ///< The address from which the message was sent. 112 | void *const mBlock; ///< Pointer to the memory block containing the message. 113 | const uint32_t mBlockSize; ///< Total size of the message memory block in bytes. 114 | }; 115 | 116 | 117 | } // namespace Detail 118 | } // namespace Theron 119 | 120 | 121 | #endif // THERON_DETAIL_MESSAGES_IMESSAGE_H 122 | -------------------------------------------------------------------------------- /Include/Theron/Detail/Messages/MessageCreator.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) by Ashton Mason. See LICENSE.txt for licensing information. 2 | #ifndef THERON_DETAIL_MESSAGES_MESSAGECREATOR_H 3 | #define THERON_DETAIL_MESSAGES_MESSAGECREATOR_H 4 | 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include 12 | #include 13 | 14 | 15 | namespace Theron 16 | { 17 | namespace Detail 18 | { 19 | 20 | 21 | /** 22 | Helper class that constructs and destroys Theron's internal message objects. 23 | */ 24 | class MessageCreator 25 | { 26 | public: 27 | 28 | /** 29 | Allocates and constructs a message with the given value and from address. 30 | */ 31 | template 32 | inline static Message *Create( 33 | IAllocator *const messageAllocator, 34 | const ValueType &value, 35 | const Address &from); 36 | 37 | /** 38 | Destructs and frees a message of unknown type referenced by an interface pointer. 39 | */ 40 | inline static void Destroy( 41 | IAllocator *const messageAllocator, 42 | IMessage *const message); 43 | }; 44 | 45 | 46 | 47 | template 48 | THERON_FORCEINLINE Message *MessageCreator::Create( 49 | IAllocator *const messageAllocator, 50 | const ValueType &value, 51 | const Address &from) 52 | { 53 | typedef Message MessageType; 54 | 55 | const uint32_t blockSize(MessageType::GetSize()); 56 | const uint32_t blockAlignment(MessageType::GetAlignment()); 57 | 58 | // Allocate a message. It'll be deleted by the actor after it's been handled. 59 | // We allocate a block from the global free list for caching of common allocations. 60 | // The free list is thread-safe so we don't need to lock it ourselves. 61 | void *const block = messageAllocator->AllocateAligned(blockSize, blockAlignment); 62 | if (block) 63 | { 64 | return MessageType::Initialize(block, value, from); 65 | } 66 | 67 | return 0; 68 | } 69 | 70 | 71 | THERON_FORCEINLINE void MessageCreator::Destroy( 72 | IAllocator *const messageAllocator, 73 | IMessage *const message) 74 | { 75 | // Call release on the message to give it chance to destruct its value type. 76 | message->Release(); 77 | 78 | // Destruct the message object itself. 79 | // This calls the derived Message class destructor by virtual function magic. 80 | message->~IMessage(); 81 | 82 | // Return the block to the global free list. 83 | messageAllocator->Free(message->GetBlock(), message->GetBlockSize()); 84 | } 85 | 86 | 87 | } // namespace Detail 88 | } // namespace Theron 89 | 90 | 91 | #endif // THERON_DETAIL_MESSAGES_MESSAGECREATOR_H 92 | -------------------------------------------------------------------------------- /Include/Theron/Detail/Messages/MessageSize.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) by Ashton Mason. See LICENSE.txt for licensing information. 2 | #ifndef THERON_DETAIL_MESSAGES_MESSAGESIZE_H 3 | #define THERON_DETAIL_MESSAGES_MESSAGESIZE_H 4 | 5 | 6 | #include 7 | #include 8 | 9 | 10 | namespace Theron 11 | { 12 | namespace Detail 13 | { 14 | 15 | 16 | /** 17 | \brief Helper that tells us the allocated size of a message value type. 18 | The point really is to do the job of rounding up 'empty' allocations consistently in one place. 19 | */ 20 | template 21 | class MessageSize 22 | { 23 | public: 24 | 25 | THERON_FORCEINLINE static uint32_t GetSize() 26 | { 27 | uint32_t valueSize(sizeof(ValueType)); 28 | const uint32_t minimumAllocationSize(4); 29 | 30 | // Empty structs passed as message values have a size of one byte, which we don't like. 31 | // To be on the safe side we round every allocation up to at least four bytes. 32 | // If we don't then the data that follows won't be word-aligned. 33 | if (valueSize < minimumAllocationSize) 34 | { 35 | valueSize = minimumAllocationSize; 36 | } 37 | 38 | return valueSize; 39 | } 40 | 41 | private: 42 | 43 | MessageSize(); 44 | MessageSize(const MessageSize &other); 45 | MessageSize &operator=(const MessageSize &other); 46 | }; 47 | 48 | 49 | } // namespace Detail 50 | } // namespace Theron 51 | 52 | 53 | #endif // THERON_DETAIL_MESSAGES_MESSAGESIZE_H 54 | 55 | -------------------------------------------------------------------------------- /Include/Theron/Detail/Messages/MessageTraits.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) by Ashton Mason. See LICENSE.txt for licensing information. 2 | #ifndef THERON_DETAIL_MESSAGES_MESSAGETRAITS_H 3 | #define THERON_DETAIL_MESSAGES_MESSAGETRAITS_H 4 | 5 | 6 | namespace Theron 7 | { 8 | namespace Detail 9 | { 10 | 11 | 12 | /** 13 | \brief Traits template that stores meta-information about message types. 14 | 15 | The MessageTraits template can be specialized for individual message types 16 | in order to label the types with their string names. 17 | By storing the name of the message type in every sent message, Theron is 18 | able to match the type with the types expected by message handlers 19 | registered in the receiving actor. 20 | 21 | The default implementation defines a null pointer (no name) for all types. 22 | The null pointer is a reserved value and implies that the type has no explicit name. 23 | Types with null names are matched by means of dynamic_cast, which 24 | relies on RTTI (Runtime Type Information - the automatic storing of a 25 | type identifier in every class). By default Theron uses RTTI exclusively. 26 | 27 | The availability of RTTI is a compilation option, usually on by default 28 | and disabled by means of an optional compiler flag. It introduces a small 29 | size overhead into every class due to the need to store a hidden identifier to 30 | identify the class's type. Note that this overhead is applied to all classes 31 | and not just messages within Theron. The overhead is not normally a problem, 32 | however in applications with tightly constrained memory requirements (such as 33 | embedded environments and games consoles) it is undesirable. 34 | 35 | The dependency on RTTI can be avoided by specifying non-null names 36 | for all message types used in the application. Users can define 37 | specializations of the traits template for their own message types, with 38 | non-zero name pointers. Doing so causes the type names stored with every 39 | sent message to be populated with the registered names of the types. 40 | If names are provided for all message types then the names are used for type 41 | matching, instead of the built-in C++ RTTI. This then allows RTTI to be disabled 42 | in the application build. 43 | 44 | The \ref THERON_REGISTER_MESSAGE macro can be used as a shorthand mechanism 45 | for registering automatically-generated names with message types. 46 | 47 | \note If type names are used, then unique names must be specified for \em all 48 | message types. Failure to specify a valid, unique name for one or more message 49 | types will result in undefined behavior (usually caught by asserts). Although 50 | type names must be unique and non-null, their values are arbitrary. 51 | 52 | \tparam ValueType The message type for which the traits are defined. 53 | \see THERON_REGISTER_MESSAGE 54 | */ 55 | template 56 | struct MessageTraits 57 | { 58 | /** 59 | \brief Indicates whether the message type has an explicit name. 60 | Message types for which have valid type names are identified 61 | using their names rather than with built-in C++ Runtime Type Information 62 | (RTTI) via dynamic_cast. 63 | */ 64 | static const bool HAS_TYPE_NAME = false; 65 | 66 | /** 67 | \brief The unique name of the type. 68 | */ 69 | static const char *const TYPE_NAME; 70 | }; 71 | 72 | 73 | template 74 | const char *const MessageTraits::TYPE_NAME = 0; 75 | 76 | 77 | } // namespace Detail 78 | } // namespace Theron 79 | 80 | 81 | #endif // THERON_DETAIL_MESSAGES_MESSAGETRAITS_H 82 | -------------------------------------------------------------------------------- /Include/Theron/Detail/Network/Index.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) by Ashton Mason. See LICENSE.txt for licensing information. 2 | #ifndef THERON_DETAIL_NETWORK_INDEX_H 3 | #define THERON_DETAIL_NETWORK_INDEX_H 4 | 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | 11 | namespace Theron 12 | { 13 | namespace Detail 14 | { 15 | 16 | 17 | /** 18 | \brief Union that combines a framework index and a mailbox index. 19 | */ 20 | union Index 21 | { 22 | THERON_FORCEINLINE Index() : mUInt32(0) 23 | { 24 | } 25 | 26 | THERON_FORCEINLINE Index(const uint32_t framework, const uint32_t index) : mUInt32(0) 27 | { 28 | mComponents.mFramework = framework; 29 | mComponents.mIndex = index; 30 | } 31 | 32 | THERON_FORCEINLINE Index(const Index &other) : mUInt32(other.mUInt32) 33 | { 34 | } 35 | 36 | THERON_FORCEINLINE Index &operator=(const Index &other) 37 | { 38 | mUInt32 = other.mUInt32; 39 | return *this; 40 | } 41 | 42 | THERON_FORCEINLINE bool operator==(const Index &other) const 43 | { 44 | return (mUInt32 == other.mUInt32); 45 | } 46 | 47 | THERON_FORCEINLINE bool operator!=(const Index &other) const 48 | { 49 | return (mUInt32 != other.mUInt32); 50 | } 51 | 52 | THERON_FORCEINLINE bool operator<(const Index &other) const 53 | { 54 | return (mUInt32 < other.mUInt32); 55 | } 56 | 57 | uint32_t mUInt32; ///< Unsigned 32-bit value. 58 | 59 | struct 60 | { 61 | uint32_t mFramework : 12; ///< Integer index identifying the framework within the local process (zero indicates a receiver). 62 | uint32_t mIndex : 20; ///< Integer index of the actor within the framework (or receiver within the process). 63 | 64 | } mComponents; 65 | }; 66 | 67 | 68 | } // namespace Detail 69 | } // namespace Theron 70 | 71 | 72 | #endif // THERON_DETAIL_NETWORK_INDEX_H 73 | -------------------------------------------------------------------------------- /Include/Theron/Detail/Network/NameGenerator.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) by Ashton Mason. See LICENSE.txt for licensing information. 2 | #ifndef THERON_DETAIL_NETWORK_NAMEGENERATOR_H 3 | #define THERON_DETAIL_NETWORK_NAMEGENERATOR_H 4 | 5 | 6 | #include 7 | #include 8 | 9 | #include 10 | #include 11 | #include 12 | 13 | 14 | #ifdef _MSC_VER 15 | #pragma warning(push) 16 | #pragma warning (disable:4996) // function or variable may be unsafe. 17 | #endif //_MSC_VER 18 | 19 | 20 | namespace Theron 21 | { 22 | namespace Detail 23 | { 24 | 25 | 26 | /** 27 | Generates string names from numbers. 28 | */ 29 | class NameGenerator 30 | { 31 | public: 32 | 33 | inline static void Generate( 34 | char *const buffer, 35 | const uint32_t id) 36 | { 37 | THERON_ASSERT(buffer); 38 | sprintf(buffer, "%x", id); 39 | } 40 | 41 | inline static void Combine( 42 | char *const buffer, 43 | const uint32_t bufferSize, 44 | const char *const rawName, 45 | const char *const frameworkName, 46 | const char *const networkName) 47 | { 48 | THERON_ASSERT(buffer); 49 | THERON_ASSERT(rawName); 50 | 51 | if (strlen(rawName) + 1 < bufferSize) 52 | { 53 | strcpy(buffer, rawName); 54 | } 55 | 56 | if (frameworkName && strlen(buffer) + strlen(frameworkName) + 2 < bufferSize) 57 | { 58 | strcat(buffer, "."); 59 | strcat(buffer, frameworkName); 60 | } 61 | 62 | if (networkName && strlen(buffer) + strlen(networkName) + 2 < bufferSize) 63 | { 64 | strcat(buffer, "."); 65 | strcat(buffer, networkName); 66 | } 67 | } 68 | }; 69 | 70 | 71 | } // namespace Detail 72 | } // namespace Theron 73 | 74 | 75 | #ifdef _MSC_VER 76 | #pragma warning(pop) 77 | #endif //_MSC_VER 78 | 79 | 80 | #endif // THERON_DETAIL_NETWORK_NAMEGENERATOR_H 81 | -------------------------------------------------------------------------------- /Include/Theron/Detail/Scheduler/BlockingMonitor.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) by Ashton Mason. See LICENSE.txt for licensing information. 2 | #ifndef THERON_DETAIL_SCHEDULER_BLOCKINGMONITOR_H 3 | #define THERON_DETAIL_SCHEDULER_BLOCKINGMONITOR_H 4 | 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #include 13 | #include 14 | #include 15 | 16 | 17 | #ifdef _MSC_VER 18 | #pragma warning(push) 19 | #pragma warning (disable:4324) // structure was padded due to __declspec(align()) 20 | #endif //_MSC_VER 21 | 22 | 23 | namespace Theron 24 | { 25 | namespace Detail 26 | { 27 | 28 | 29 | /** 30 | \brief Blocking monitor thread synchronization primitive based on a condition variable. 31 | */ 32 | class BlockingMonitor 33 | { 34 | public: 35 | 36 | struct Context 37 | { 38 | }; 39 | 40 | class LockType 41 | { 42 | public: 43 | 44 | friend class BlockingMonitor; 45 | 46 | THERON_FORCEINLINE explicit LockType(BlockingMonitor &monitor) : mLock(monitor.mCondition.GetMutex()) 47 | { 48 | } 49 | 50 | THERON_FORCEINLINE void Unlock() 51 | { 52 | mLock.Unlock(); 53 | } 54 | 55 | THERON_FORCEINLINE void Relock() 56 | { 57 | mLock.Relock(); 58 | } 59 | 60 | private: 61 | 62 | LockType(const LockType &other); 63 | LockType &operator=(const LockType &other); 64 | 65 | Lock mLock; 66 | }; 67 | 68 | friend class LockType; 69 | 70 | /** 71 | Constructs a monitor with the given yield strategy hint. 72 | */ 73 | inline explicit BlockingMonitor(const YieldStrategy yieldStrategy); 74 | 75 | /** 76 | Initializes the context structure of a worker thread. 77 | \note The calling thread must be a worker thread. 78 | */ 79 | inline void InitializeWorkerContext(Context *const context); 80 | 81 | /** 82 | Resets the yield backoff following a successful acquire. 83 | \note The calling thread should not hold a lock. 84 | */ 85 | inline void ResetYield(Context *const context); 86 | 87 | /** 88 | Wakes at most one waiting thread. 89 | \note The calling thread should hold a lock while changing the protected state but should release it before calling Pulse. 90 | */ 91 | inline void Pulse(); 92 | 93 | /** 94 | Wakes all waiting threads. 95 | \note The calling thread should hold a lock while changing the protected state but should release it before calling PulseAll. 96 | */ 97 | inline void PulseAll(); 98 | 99 | /** 100 | Puts the calling thread to sleep until it is woken by a pulse. 101 | \note The calling thread should hold a lock and should pass the lock as a parameter. 102 | */ 103 | inline void Wait(Context *const context, LockType &lock); 104 | 105 | private: 106 | 107 | BlockingMonitor(const BlockingMonitor &other); 108 | BlockingMonitor &operator=(const BlockingMonitor &other); 109 | 110 | mutable Condition mCondition; 111 | }; 112 | 113 | 114 | inline BlockingMonitor::BlockingMonitor(const YieldStrategy /*yieldStrategy*/) 115 | { 116 | } 117 | 118 | 119 | inline void BlockingMonitor::InitializeWorkerContext(Context *const /*context*/) 120 | { 121 | } 122 | 123 | 124 | THERON_FORCEINLINE void BlockingMonitor::ResetYield(Context *const /*context*/) 125 | { 126 | } 127 | 128 | 129 | THERON_FORCEINLINE void BlockingMonitor::Pulse() 130 | { 131 | mCondition.Pulse(); 132 | } 133 | 134 | 135 | THERON_FORCEINLINE void BlockingMonitor::PulseAll() 136 | { 137 | mCondition.PulseAll(); 138 | } 139 | 140 | 141 | THERON_FORCEINLINE void BlockingMonitor::Wait(Context *const /*context*/, LockType &lock) 142 | { 143 | // The lock is released and reacquired atomically inside Wait(). 144 | mCondition.Wait(lock.mLock); 145 | } 146 | 147 | 148 | } // namespace Detail 149 | } // namespace Theron 150 | 151 | 152 | #ifdef _MSC_VER 153 | #pragma warning(pop) 154 | #endif //_MSC_VER 155 | 156 | 157 | #endif // THERON_DETAIL_SCHEDULER_BLOCKINGMONITOR_H 158 | -------------------------------------------------------------------------------- /Include/Theron/Detail/Scheduler/IScheduler.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) by Ashton Mason. See LICENSE.txt for licensing information. 2 | #ifndef THERON_DETAIL_SCHEDULER_ISCHEDULER_H 3 | #define THERON_DETAIL_SCHEDULER_ISCHEDULER_H 4 | 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include 12 | #include 13 | #include 14 | 15 | 16 | namespace Theron 17 | { 18 | namespace Detail 19 | { 20 | 21 | 22 | class FallbackHandlerCollection; 23 | class MailboxContext; 24 | 25 | 26 | /** 27 | \brief Mailbox scheduler interface. 28 | 29 | The Scheduler class itself is templated to allow the use of different queue implementations. 30 | This interface allows instantiations of the template against different queue types to be 31 | referenced polymorphically. 32 | */ 33 | class IScheduler 34 | { 35 | public: 36 | 37 | /** 38 | Default constructor. 39 | */ 40 | IScheduler() 41 | { 42 | } 43 | 44 | /** 45 | Virtual destructor. 46 | */ 47 | virtual ~IScheduler() 48 | { 49 | } 50 | 51 | /** 52 | Initializes a scheduler at start of day. 53 | */ 54 | virtual void Initialize(const uint32_t threadCount) = 0; 55 | 56 | /** 57 | Tears down the scheduler prior to destruction. 58 | */ 59 | virtual void Release() = 0; 60 | 61 | /** 62 | Notifies the scheduler that a worker thread is about to start executing a message handler. 63 | */ 64 | virtual void BeginHandler(MailboxContext *const mailboxContext, IMessageHandler *const messageHandler) = 0; 65 | 66 | /** 67 | Notifies the scheduler that a worker thread has finished executing a message handler. 68 | */ 69 | virtual void EndHandler(MailboxContext *const mailboxContext, IMessageHandler *const messageHandler) = 0; 70 | 71 | /** 72 | Schedules for processing a mailbox that has received a message. 73 | */ 74 | virtual void Schedule(MailboxContext *const mailboxContext, Mailbox *const mailbox) = 0; 75 | 76 | /** 77 | Sets a maximum limit on the number of worker threads enabled in the scheduler. 78 | */ 79 | virtual void SetMaxThreads(const uint32_t count) = 0; 80 | 81 | /** 82 | Sets a minimum limit on the number of worker threads enabled in the scheduler. 83 | */ 84 | virtual void SetMinThreads(const uint32_t count) = 0; 85 | 86 | /** 87 | Gets the current maximum limit on the number of worker threads enabled in the scheduler. 88 | */ 89 | virtual uint32_t GetMaxThreads() const = 0; 90 | 91 | /** 92 | Gets the current minimum limit on the number of worker threads enabled in the scheduler. 93 | */ 94 | virtual uint32_t GetMinThreads() const = 0; 95 | 96 | /** 97 | Gets the current number of worker threads enabled in the scheduler. 98 | */ 99 | virtual uint32_t GetNumThreads() const = 0; 100 | 101 | /** 102 | Gets the highest number of worker threads that was ever enabled at one time in the scheduler. 103 | */ 104 | virtual uint32_t GetPeakThreads() const = 0; 105 | 106 | /** 107 | Resets all the scheduler's internal event counters to zero. 108 | */ 109 | virtual void ResetCounters() = 0; 110 | 111 | /** 112 | Gets the current value of a specified event counter, accumulated for all worker threads). 113 | */ 114 | virtual uint32_t GetCounterValue(const uint32_t counter) const = 0; 115 | 116 | /** 117 | Gets the current value of a specified event counter, for each worker thread individually. 118 | */ 119 | virtual uint32_t GetPerThreadCounterValues( 120 | const uint32_t counter, 121 | uint32_t *const perThreadCounts, 122 | const uint32_t maxCounts) const = 0; 123 | 124 | private: 125 | 126 | IScheduler(const IScheduler &other); 127 | IScheduler &operator=(const IScheduler &other); 128 | }; 129 | 130 | 131 | } // namespace Detail 132 | } // namespace Theron 133 | 134 | 135 | #endif // THERON_DETAIL_SCHEDULER_ISCHEDULER_H 136 | -------------------------------------------------------------------------------- /Include/Theron/Detail/Scheduler/MailboxContext.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) by Ashton Mason. See LICENSE.txt for licensing information. 2 | #ifndef THERON_DETAIL_SCHEDULER_MAILBOXCONTEXT_H 3 | #define THERON_DETAIL_SCHEDULER_MAILBOXCONTEXT_H 4 | 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | #include 11 | #include 12 | #include 13 | 14 | 15 | namespace Theron 16 | { 17 | namespace Detail 18 | { 19 | 20 | 21 | /** 22 | Context structure holding data used by a worker thread to process mailboxes. 23 | 24 | \note The members of a single context are all accessed only by one worker thread 25 | so we don't need to worry about shared writes, including false sharing. 26 | */ 27 | class MailboxContext 28 | { 29 | public: 30 | 31 | /** 32 | Constructor. 33 | */ 34 | inline MailboxContext() : 35 | mScheduler(0), 36 | mQueueContext(0), 37 | mFallbackHandlers(0), 38 | mMessageAllocator(0), 39 | mMailbox(0), 40 | mPredictedSendCount(0), 41 | mSendCount(0) 42 | { 43 | } 44 | 45 | IScheduler *mScheduler; ///< Pointer to the associated scheduler. 46 | void *mQueueContext; ///< Pointer to the associated queue context. 47 | FallbackHandlerCollection *mFallbackHandlers; ///< Pointer to fallback handlers for undelivered messages. 48 | IAllocator *mMessageAllocator; ///< Pointer to message memory block allocator. 49 | Mailbox *mMailbox; ///< Pointer to the mailbox that is being processed. 50 | uint32_t mPredictedSendCount; ///< Number of messages predicted to be sent by the handler. 51 | uint32_t mSendCount; ///< Messages sent so far by the handler being executed. 52 | 53 | private: 54 | 55 | MailboxContext(const MailboxContext &other); 56 | MailboxContext &operator=(const MailboxContext &other); 57 | }; 58 | 59 | 60 | } // namespace Detail 61 | } // namespace Theron 62 | 63 | 64 | #endif // THERON_DETAIL_SCHEDULER_MAILBOXCONTEXT_H 65 | -------------------------------------------------------------------------------- /Include/Theron/Detail/Scheduler/MailboxProcessor.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) by Ashton Mason. See LICENSE.txt for licensing information. 2 | #ifndef THERON_DETAIL_SCHEDULER_MAILBOXPROCESSOR_H 3 | #define THERON_DETAIL_SCHEDULER_MAILBOXPROCESSOR_H 4 | 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | 17 | namespace Theron 18 | { 19 | 20 | 21 | class Actor; 22 | 23 | 24 | namespace Detail 25 | { 26 | 27 | 28 | /** 29 | Processes mailboxes that have received messages. 30 | */ 31 | class MailboxProcessor 32 | { 33 | public: 34 | 35 | inline static void Process(WorkerContext *const workerContext, Mailbox *const mailbox); 36 | 37 | private: 38 | 39 | MailboxProcessor(const MailboxProcessor &other); 40 | MailboxProcessor &operator=(const MailboxProcessor &other); 41 | }; 42 | 43 | 44 | THERON_FORCEINLINE void MailboxProcessor::Process(WorkerContext *const workerContext, Mailbox *const mailbox) 45 | { 46 | // Load the context data from the worker thread's mailbox context. 47 | MailboxContext *const mailboxContext(&workerContext->mMailboxContext); 48 | FallbackHandlerCollection *const fallbackHandlers(mailboxContext->mFallbackHandlers); 49 | IAllocator *const messageAllocator(mailboxContext->mMessageAllocator); 50 | 51 | THERON_ASSERT(fallbackHandlers); 52 | THERON_ASSERT(messageAllocator); 53 | 54 | // Remember the mailbox we're processing in the context so we can query it. 55 | mailboxContext->mMailbox = mailbox; 56 | 57 | // Pin the mailbox and get the registered actor and the first queued message. 58 | // At this point the mailbox shouldn't be enqueued in any other work items, 59 | // even if it contains more than one unprocessed message. This ensures that 60 | // each mailbox is only processed by one worker thread at a time. 61 | mailbox->Lock(); 62 | mailbox->Pin(); 63 | Actor *const actor(mailbox->GetActor()); 64 | IMessage *const message(mailbox->Front()); 65 | mailbox->Unlock(); 66 | 67 | // If an actor is registered at the mailbox then process it. 68 | if (actor) 69 | { 70 | actor->ProcessMessage(mailboxContext, fallbackHandlers, message); 71 | } 72 | else 73 | { 74 | fallbackHandlers->Handle(message); 75 | } 76 | 77 | // Pop the message we just processed from the mailbox, then check whether the 78 | // mailbox is now empty, and reschedule the mailbox if it's not. 79 | // The locking of the mailbox here and in the main scheduling ensures that 80 | // mailboxes are always enqueued if they have unprocessed messages, but at most 81 | // once at any time. 82 | mailbox->Lock(); 83 | mailbox->Unpin(); 84 | mailbox->Pop(); 85 | 86 | if (!mailbox->Empty()) 87 | { 88 | mailboxContext->mScheduler->Schedule(mailboxContext, mailbox); 89 | } 90 | 91 | mailbox->Unlock(); 92 | 93 | // Destroy the message, but only after we've popped it from the queue. 94 | MessageCreator::Destroy(messageAllocator, message); 95 | } 96 | 97 | 98 | } // namespace Detail 99 | } // namespace Theron 100 | 101 | 102 | #endif // THERON_DETAIL_SCHEDULER_MAILBOXPROCESSOR_H 103 | -------------------------------------------------------------------------------- /Include/Theron/Detail/Scheduler/SchedulerHints.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) by Ashton Mason. See LICENSE.txt for licensing information. 2 | #ifndef THERON_DETAIL_SCHEDULER_SCHEDULERHINTS_H 3 | #define THERON_DETAIL_SCHEDULER_SCHEDULERHINTS_H 4 | 5 | 6 | #include 7 | #include 8 | 9 | 10 | namespace Theron 11 | { 12 | namespace Detail 13 | { 14 | 15 | 16 | /** 17 | Wraps up various bits of information available to scheduler queuing policies. 18 | */ 19 | class SchedulerHints 20 | { 21 | public: 22 | 23 | THERON_FORCEINLINE SchedulerHints() 24 | { 25 | } 26 | 27 | bool mSend; ///< Indicates whether the mailbox is being scheduled due to being sent a message. 28 | uint32_t mPredictedSendCount; ///< Predicts the number of messages that will be sent by the current handler. 29 | uint32_t mSendIndex; ///< Index of this message send within the current handler. 30 | uint32_t mMessageCount; ///< Number of messages queued in the mailbox that is currently being processed. 31 | 32 | private: 33 | 34 | SchedulerHints(const SchedulerHints &other); 35 | SchedulerHints &operator=(const SchedulerHints &other); 36 | }; 37 | 38 | 39 | } // namespace Detail 40 | } // namespace Theron 41 | 42 | 43 | #endif // THERON_DETAIL_SCHEDULER_SCHEDULERHINTS_H 44 | -------------------------------------------------------------------------------- /Include/Theron/Detail/Scheduler/WorkerContext.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) by Ashton Mason. See LICENSE.txt for licensing information. 2 | #ifndef THERON_DETAIL_SCHEDULER_WORKERCONTEXT_H 3 | #define THERON_DETAIL_SCHEDULER_WORKERCONTEXT_H 4 | 5 | 6 | #include 7 | #include 8 | 9 | 10 | #ifdef _MSC_VER 11 | #pragma warning(push) 12 | #pragma warning (disable:4324) // structure was padded due to __declspec(align()) 13 | #endif //_MSC_VER 14 | 15 | 16 | namespace Theron 17 | { 18 | namespace Detail 19 | { 20 | 21 | 22 | /** 23 | Per-worker thread context structure holding data used by a worker thread. 24 | This is a wrapper used to hold a couple of different pieces of context data. 25 | */ 26 | class WorkerContext 27 | { 28 | public: 29 | 30 | /** 31 | Constructor. 32 | */ 33 | inline WorkerContext() 34 | { 35 | } 36 | 37 | CachingAllocator<> mMessageCache; ///< Per-thread cache of message memory blocks. 38 | MailboxContext mMailboxContext; ///< Per-thread context for mailbox processing. 39 | 40 | private: 41 | 42 | WorkerContext(const WorkerContext &other); 43 | WorkerContext &operator=(const WorkerContext &other); 44 | }; 45 | 46 | 47 | } // namespace Detail 48 | } // namespace Theron 49 | 50 | 51 | #ifdef _MSC_VER 52 | #pragma warning(pop) 53 | #endif //_MSC_VER 54 | 55 | 56 | #endif // THERON_DETAIL_SCHEDULER_WORKERCONTEXT_H 57 | -------------------------------------------------------------------------------- /Include/Theron/Detail/Scheduler/YieldImplementation.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) by Ashton Mason. See LICENSE.txt for licensing information. 2 | #ifndef THERON_DETAIL_SCHEDULER_YIELDIMPLEMENTATION_H 3 | #define THERON_DETAIL_SCHEDULER_YIELDIMPLEMENTATION_H 4 | 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | 11 | namespace Theron 12 | { 13 | namespace Detail 14 | { 15 | 16 | 17 | /** 18 | A 'yield' function which can be called to yield a waiting thread so that 19 | other threads also accessing a contested resource can progress. 20 | */ 21 | typedef void (* YieldFunction)(const uint32_t counter); 22 | 23 | 24 | /** 25 | Mailbox processor thread yield strategy policy implementation. 26 | */ 27 | class YieldImplementation 28 | { 29 | public: 30 | 31 | inline explicit YieldImplementation() : 32 | mCounter(0), 33 | mYieldFunction(0) 34 | { 35 | } 36 | 37 | THERON_FORCEINLINE void SetYieldFunction(YieldFunction yieldFunction) 38 | { 39 | mYieldFunction = yieldFunction; 40 | } 41 | 42 | THERON_FORCEINLINE void Reset() 43 | { 44 | mCounter = 0; 45 | } 46 | 47 | THERON_FORCEINLINE void Execute() 48 | { 49 | THERON_ASSERT(mYieldFunction); 50 | (*mYieldFunction)(mCounter); 51 | ++mCounter; 52 | } 53 | 54 | private: 55 | 56 | uint32_t mCounter; 57 | YieldFunction mYieldFunction; 58 | }; 59 | 60 | 61 | } // namespace Detail 62 | } // namespace Theron 63 | 64 | 65 | #endif // THERON_DETAIL_SCHEDULER_YIELDIMPLEMENTATION_H 66 | -------------------------------------------------------------------------------- /Include/Theron/Detail/Scheduler/YieldPolicy.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) by Ashton Mason. See LICENSE.txt for licensing information. 2 | #ifndef THERON_DETAIL_SCHEDULER_YIELDPOLICY_H 3 | #define THERON_DETAIL_SCHEDULER_YIELDPOLICY_H 4 | 5 | 6 | #include 7 | #include 8 | 9 | 10 | namespace Theron 11 | { 12 | namespace Detail 13 | { 14 | 15 | 16 | /** 17 | Yield strategy policy implementations. 18 | */ 19 | class YieldPolicy 20 | { 21 | public: 22 | 23 | /** 24 | Spin, but yield to other threads after a timeout. 25 | */ 26 | static void Hybrid(const uint32_t counter); 27 | 28 | /** 29 | Spin indefinitely (or busy-wait), with no yielding to other threads. 30 | */ 31 | static void Spin(const uint32_t counter); 32 | 33 | private: 34 | 35 | YieldPolicy(); 36 | YieldPolicy(const YieldPolicy &other); 37 | YieldPolicy &operator=(const YieldPolicy &other); 38 | }; 39 | 40 | 41 | } // namespace Detail 42 | } // namespace Theron 43 | 44 | 45 | #endif // THERON_DETAIL_SCHEDULER_YIELDPOLICY_H 46 | -------------------------------------------------------------------------------- /Include/Theron/Detail/Strings/String.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) by Ashton Mason. See LICENSE.txt for licensing information. 2 | #ifndef THERON_DETAIL_STRINGS_STRING_H 3 | #define THERON_DETAIL_STRINGS_STRING_H 4 | 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | #include 11 | 12 | 13 | namespace Theron 14 | { 15 | namespace Detail 16 | { 17 | 18 | 19 | /** 20 | A copyable string type that is a lightweight wrapper around a pooled string. 21 | */ 22 | class String 23 | { 24 | public: 25 | 26 | /** 27 | Default constructor. 28 | Constructs a null string with no value. 29 | */ 30 | THERON_FORCEINLINE String() : mValue(0) 31 | { 32 | } 33 | 34 | /** 35 | Explicit constructor. 36 | */ 37 | THERON_FORCEINLINE explicit String(const char *const str) : mValue(0) 38 | { 39 | if (str) 40 | { 41 | mValue = StringPool::Get(str); 42 | } 43 | } 44 | 45 | /** 46 | Returns true if the string has no value. 47 | */ 48 | THERON_FORCEINLINE bool IsNull() const 49 | { 50 | return (mValue == 0); 51 | } 52 | 53 | /** 54 | Gets the value of the string. 55 | \note Returns a null pointer if the string is null. 56 | */ 57 | THERON_FORCEINLINE const char *GetValue() const 58 | { 59 | return mValue; 60 | } 61 | 62 | /** 63 | Equality operator. 64 | */ 65 | THERON_FORCEINLINE bool operator==(const String &other) const 66 | { 67 | // Pooled strings are unique so we can compare their addresses. 68 | // This works for null strings too, whose value pointers are zero. 69 | return (mValue == other.mValue); 70 | } 71 | 72 | /** 73 | Inequality operator. 74 | */ 75 | THERON_FORCEINLINE bool operator!=(const String &other) const 76 | { 77 | return !operator==(other); 78 | } 79 | 80 | /** 81 | Less-than operator, mainly for sorted containers. 82 | Defines an arbitrary, non-alphabetical partial ordering. 83 | */ 84 | THERON_FORCEINLINE bool operator<(const String &other) const 85 | { 86 | // Arbitrary less-than based on cheap pointer comparison. 87 | // This works for null strings too, whose value pointers are zero. 88 | return (mValue < other.mValue); 89 | } 90 | 91 | private: 92 | 93 | const char *mValue; 94 | }; 95 | 96 | 97 | } // namespace Detail 98 | } // namespace Theron 99 | 100 | 101 | #endif // THERON_DETAIL_STRINGS_STRING_H 102 | -------------------------------------------------------------------------------- /Include/Theron/Detail/Strings/StringHash.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) by Ashton Mason. See LICENSE.txt for licensing information. 2 | #ifndef THERON_DETAIL_STRINGS_STRINGHASH_H 3 | #define THERON_DETAIL_STRINGS_STRINGHASH_H 4 | 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | 11 | namespace Theron 12 | { 13 | namespace Detail 14 | { 15 | 16 | 17 | /** 18 | \brief Simple hash utility for C strings. 19 | */ 20 | class StringHash 21 | { 22 | public: 23 | 24 | enum 25 | { 26 | RANGE = 256 27 | }; 28 | 29 | THERON_FORCEINLINE static uint32_t Compute(const char *const str) 30 | { 31 | THERON_ASSERT(str); 32 | 33 | // XOR the first n characters of the string together. 34 | const char *const end(str + 64); 35 | 36 | const char *ch(str); 37 | uint8_t hash(0); 38 | 39 | while (ch != end && *ch != '\0') 40 | { 41 | hash ^= static_cast(*ch); 42 | ++ch; 43 | } 44 | 45 | return static_cast(hash); 46 | } 47 | }; 48 | 49 | 50 | } // namespace Detail 51 | } // namespace Theron 52 | 53 | 54 | #endif // THERON_DETAIL_STRINGS_STRINGHASH_H 55 | -------------------------------------------------------------------------------- /Include/Theron/Detail/Threading/Clock.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) by Ashton Mason. See LICENSE.txt for licensing information. 2 | #ifndef THERON_DETAIL_THREADING_CLOCK_H 3 | #define THERON_DETAIL_THREADING_CLOCK_H 4 | 5 | 6 | #include 7 | #include 8 | 9 | 10 | #if THERON_MSVC 11 | #pragma warning(push,0) 12 | #endif // THERON_MSVC 13 | 14 | #if THERON_WINDOWS 15 | #include 16 | #elif THERON_POSIX 17 | #include 18 | #include 19 | #endif 20 | 21 | #if THERON_MSVC 22 | #pragma warning(pop) 23 | #endif // THERON_MSVC 24 | 25 | 26 | namespace Theron 27 | { 28 | namespace Detail 29 | { 30 | 31 | 32 | /** 33 | Static helper class that queries system performance timers. 34 | */ 35 | class Clock 36 | { 37 | public: 38 | 39 | /** 40 | Queries the clock for a timestamp in ticks. 41 | The time-length of a tick is implementation-dependent. 42 | */ 43 | THERON_FORCEINLINE static uint64_t GetTicks() 44 | { 45 | #if THERON_WINDOWS 46 | 47 | // The 'ticks' are cycles in the Windows implementation. 48 | LARGE_INTEGER counter; 49 | QueryPerformanceCounter(&counter); 50 | return (uint64_t) counter.QuadPart; 51 | 52 | #elif THERON_POSIX 53 | 54 | // The 'ticks' are nanoseconds in the POSIX implementation. 55 | struct timespec ts; 56 | clock_gettime(CLOCK_MONOTONIC, &ts); 57 | return (uint64_t) ts.tv_sec * NANOSECONDS_PER_SECOND + (uint64_t) ts.tv_nsec; 58 | 59 | #else 60 | 61 | return 0; 62 | 63 | #endif 64 | } 65 | 66 | /** 67 | Queries the clock for its resolution in ticks-per-second. 68 | */ 69 | THERON_FORCEINLINE static uint64_t GetFrequency() 70 | { 71 | return mStatic.mTicksPerSecond; 72 | } 73 | 74 | private: 75 | 76 | struct Static 77 | { 78 | Static(); 79 | 80 | uint64_t mTicksPerSecond; 81 | }; 82 | 83 | static const uint64_t NANOSECONDS_PER_SECOND = 1000000000ULL; 84 | static Static mStatic; 85 | }; 86 | 87 | 88 | } // namespace Detail 89 | } // namespace Theron 90 | 91 | 92 | #endif // THERON_DETAIL_THREADING_CLOCK_H 93 | -------------------------------------------------------------------------------- /Include/Theron/Detail/Threading/Lock.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) by Ashton Mason. See LICENSE.txt for licensing information. 2 | #ifndef THERON_DETAIL_THREADING_LOCK_H 3 | #define THERON_DETAIL_THREADING_LOCK_H 4 | 5 | 6 | #include 7 | 8 | #include 9 | 10 | #if THERON_MSVC 11 | #pragma warning(push,0) 12 | #endif // THERON_MSVC 13 | 14 | #if THERON_WINDOWS 15 | #elif THERON_POSIX 16 | 17 | #include 18 | 19 | #elif THERON_BOOST 20 | 21 | #include 22 | #include 23 | 24 | #elif THERON_CPP11 25 | 26 | #include 27 | 28 | #else 29 | 30 | #error No mutex support detected. 31 | 32 | #endif 33 | 34 | #if THERON_MSVC 35 | #pragma warning(pop) 36 | #endif // THERON_MSVC 37 | 38 | 39 | namespace Theron 40 | { 41 | namespace Detail 42 | { 43 | 44 | 45 | /** 46 | Portable lock synchronization primitive. 47 | This class is a helper which allows a mutex to be locked and automatically locked within a scope. 48 | */ 49 | class Lock 50 | { 51 | public: 52 | 53 | friend class Condition; 54 | 55 | /** 56 | Constructor. Locks the given mutex object. 57 | */ 58 | THERON_FORCEINLINE explicit Lock(Mutex &mutex) : 59 | #if THERON_WINDOWS 60 | mMutex(mutex) 61 | #elif THERON_POSIX 62 | mMutex(mutex) 63 | #elif THERON_BOOST 64 | mLock(mutex.mMutex) 65 | #elif THERON_CPP11 66 | mLock(mutex.mMutex) 67 | #endif 68 | { 69 | #if THERON_WINDOWS 70 | 71 | mMutex.Lock(); 72 | 73 | #elif THERON_POSIX 74 | 75 | mMutex.Lock(); 76 | 77 | #elif THERON_BOOST 78 | 79 | // The wrapped boost::unique_lock locks the mutex itself. 80 | 81 | #elif THERON_CPP11 82 | 83 | // The wrapped std::unique_lock locks the mutex itself. 84 | 85 | #endif 86 | } 87 | 88 | /** 89 | Destructor. Automatically unlocks the locked mutex that was locked on construction. 90 | */ 91 | THERON_FORCEINLINE ~Lock() 92 | { 93 | #if THERON_WINDOWS 94 | 95 | mMutex.Unlock(); 96 | 97 | #elif THERON_POSIX 98 | 99 | mMutex.Unlock(); 100 | 101 | #elif THERON_BOOST 102 | 103 | // The wrapped boost::unique_lock unlocks the mutex itself. 104 | 105 | #elif THERON_CPP11 106 | 107 | // The wrapped std::unique_lock unlocks the mutex itself. 108 | 109 | #endif 110 | } 111 | 112 | /** 113 | Explicitly and temporarily unlocks the locked mutex. 114 | \note The caller should always call \ref Relock after this call and before destruction. 115 | */ 116 | THERON_FORCEINLINE void Unlock() 117 | { 118 | #if THERON_WINDOWS 119 | 120 | mMutex.Unlock(); 121 | 122 | #elif THERON_POSIX 123 | 124 | mMutex.Unlock(); 125 | 126 | #elif THERON_BOOST 127 | 128 | THERON_ASSERT(mLock.owns_lock() == true); 129 | mLock.unlock(); 130 | 131 | #elif THERON_CPP11 132 | 133 | THERON_ASSERT(mLock.owns_lock() == true); 134 | mLock.unlock(); 135 | 136 | #endif 137 | } 138 | 139 | /** 140 | Re-locks the associated mutex, which must have been previously unlocked with \ref Unlock. 141 | \note Relock can only be called after a preceding call to \ref Unlock. 142 | */ 143 | THERON_FORCEINLINE void Relock() 144 | { 145 | #if THERON_WINDOWS 146 | 147 | mMutex.Lock(); 148 | 149 | #elif THERON_POSIX 150 | 151 | mMutex.Lock(); 152 | 153 | #elif THERON_BOOST 154 | 155 | THERON_ASSERT(mLock.owns_lock() == false); 156 | mLock.lock(); 157 | 158 | #elif THERON_CPP11 159 | 160 | THERON_ASSERT(mLock.owns_lock() == false); 161 | mLock.lock(); 162 | 163 | #endif 164 | } 165 | 166 | private: 167 | 168 | Lock(const Lock &other); 169 | Lock &operator=(const Lock &other); 170 | 171 | #if THERON_WINDOWS 172 | 173 | Mutex &mMutex; 174 | 175 | #elif THERON_POSIX 176 | 177 | Mutex &mMutex; 178 | 179 | #elif THERON_BOOST 180 | 181 | boost::unique_lock mLock; 182 | 183 | #elif THERON_CPP11 184 | 185 | std::unique_lock mLock; 186 | 187 | #endif 188 | 189 | }; 190 | 191 | 192 | } // namespace Detail 193 | } // namespace Theron 194 | 195 | 196 | #endif // THERON_DETAIL_THREADING_LOCK_H 197 | -------------------------------------------------------------------------------- /Include/Theron/Detail/Threading/Mutex.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) by Ashton Mason. See LICENSE.txt for licensing information. 2 | #ifndef THERON_DETAIL_THREADING_MUTEX_H 3 | #define THERON_DETAIL_THREADING_MUTEX_H 4 | 5 | 6 | #include 7 | 8 | 9 | #if THERON_MSVC 10 | #pragma warning(push,0) 11 | #endif // THERON_MSVC 12 | 13 | #if THERON_WINDOWS 14 | 15 | #include 16 | 17 | #elif THERON_POSIX 18 | 19 | #include 20 | 21 | #elif THERON_BOOST 22 | 23 | #include 24 | 25 | #elif THERON_CPP11 26 | 27 | #include 28 | #include 29 | 30 | #else 31 | 32 | #error No mutex support detected. 33 | 34 | #endif 35 | 36 | #if THERON_MSVC 37 | #pragma warning(pop) 38 | #endif // THERON_MSVC 39 | 40 | 41 | namespace Theron 42 | { 43 | namespace Detail 44 | { 45 | 46 | 47 | /** 48 | Portable mutex synchronization primitive. 49 | */ 50 | class Mutex 51 | { 52 | public: 53 | 54 | friend class Condition; 55 | friend class Lock; 56 | 57 | /** 58 | Default constructor. 59 | */ 60 | THERON_FORCEINLINE Mutex() 61 | { 62 | #if THERON_WINDOWS 63 | 64 | InitializeCriticalSection(&mCriticalSection); 65 | 66 | #elif THERON_POSIX 67 | 68 | pthread_mutex_init(&mMutex, 0); 69 | 70 | #elif THERON_BOOST 71 | #elif THERON_CPP11 72 | #endif 73 | } 74 | 75 | /** 76 | Destructor. 77 | */ 78 | THERON_FORCEINLINE ~Mutex() 79 | { 80 | #if THERON_WINDOWS 81 | 82 | DeleteCriticalSection(&mCriticalSection); 83 | 84 | #elif THERON_POSIX 85 | 86 | pthread_mutex_destroy(&mMutex); 87 | 88 | #elif THERON_BOOST 89 | #elif THERON_CPP11 90 | #endif 91 | } 92 | 93 | /** 94 | Locks the mutex, guaranteeing exclusive access to a protected resource associated with it. 95 | \note This is a blocking call and should be used with care to avoid deadlocks. 96 | */ 97 | THERON_FORCEINLINE void Lock() 98 | { 99 | #if THERON_WINDOWS 100 | 101 | EnterCriticalSection(&mCriticalSection); 102 | 103 | #elif THERON_POSIX 104 | 105 | pthread_mutex_lock(&mMutex); 106 | 107 | #elif THERON_BOOST 108 | 109 | mMutex.lock(); 110 | 111 | #elif THERON_CPP11 112 | 113 | mMutex.lock(); 114 | 115 | #endif 116 | } 117 | 118 | /** 119 | Unlocks the mutex, releasing exclusive access to a protected resource associated with it. 120 | */ 121 | THERON_FORCEINLINE void Unlock() 122 | { 123 | #if THERON_WINDOWS 124 | 125 | LeaveCriticalSection(&mCriticalSection); 126 | 127 | #elif THERON_POSIX 128 | 129 | pthread_mutex_unlock(&mMutex); 130 | 131 | #elif THERON_BOOST 132 | 133 | mMutex.unlock(); 134 | 135 | #elif THERON_CPP11 136 | 137 | mMutex.unlock(); 138 | 139 | #endif 140 | } 141 | 142 | private: 143 | 144 | Mutex(const Mutex &other); 145 | Mutex &operator=(const Mutex &other); 146 | 147 | #if THERON_WINDOWS 148 | 149 | CRITICAL_SECTION mCriticalSection; 150 | 151 | #elif THERON_POSIX 152 | 153 | pthread_mutex_t mMutex; 154 | 155 | #elif THERON_BOOST 156 | 157 | boost::mutex mMutex; 158 | 159 | #elif THERON_CPP11 160 | 161 | std::mutex mMutex; 162 | 163 | #endif 164 | 165 | }; 166 | 167 | 168 | } // namespace Detail 169 | } // namespace Theron 170 | 171 | 172 | #endif // THERON_DETAIL_THREADING_MUTEX_H 173 | -------------------------------------------------------------------------------- /Include/Theron/Detail/Threading/README.txt: -------------------------------------------------------------------------------- 1 | 2 | This folder contains implementations of simple multithreading primitives. 3 | The idea here is to be able to support different implementations under the 4 | hood, through a simple common API. The provided implementations support boost::thread, 5 | std::thread and Windows threads out-of-the-box. Other implementations are possible, 6 | and could be made publically available. 7 | 8 | -------------------------------------------------------------------------------- /Include/Theron/Detail/Threading/SpinLock.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) by Ashton Mason. See LICENSE.txt for licensing information. 2 | #ifndef THERON_DETAIL_THREADING_SPINLOCK_H 3 | #define THERON_DETAIL_THREADING_SPINLOCK_H 4 | 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #if THERON_WINDOWS || THERON_BOOST || THERON_CPP11 12 | 13 | #include 14 | #include 15 | 16 | #elif THERON_POSIX 17 | 18 | #include 19 | 20 | #else 21 | 22 | #error Theron requires POSIX thread support, Boost, or Windows. 23 | 24 | #endif 25 | 26 | #ifdef _MSC_VER 27 | #pragma warning(push) 28 | #pragma warning (disable:4127) // Conditional expression is constant. 29 | #pragma warning (disable:4324) // structure was padded due to __declspec(align()) 30 | #endif //_MSC_VER 31 | 32 | 33 | namespace Theron 34 | { 35 | namespace Detail 36 | { 37 | 38 | 39 | /** 40 | A simple spinlock thread synchronization primitive. 41 | */ 42 | class THERON_PREALIGN(THERON_CACHELINE_ALIGNMENT) SpinLock 43 | { 44 | public: 45 | 46 | /** 47 | Default constructor. 48 | */ 49 | THERON_FORCEINLINE SpinLock() 50 | { 51 | #if THERON_WINDOWS || THERON_BOOST || THERON_CPP11 52 | 53 | mValue.Store(0); 54 | 55 | #elif THERON_POSIX 56 | 57 | pthread_spin_init(&mSpinLock, 0); 58 | 59 | #endif 60 | } 61 | 62 | /** 63 | Destructor. 64 | */ 65 | THERON_FORCEINLINE ~SpinLock() 66 | { 67 | #if THERON_WINDOWS || THERON_BOOST || THERON_CPP11 68 | #elif THERON_POSIX 69 | 70 | pthread_spin_destroy(&mSpinLock); 71 | 72 | #endif 73 | } 74 | 75 | /** 76 | Locks the spinlock. 77 | Locking the spinlock guarantees exclusive access to a protected resource associated with it. 78 | \note The calling thread will busy-wait and hence this method should be used with care. 79 | */ 80 | THERON_FORCEINLINE void Lock() 81 | { 82 | #if THERON_WINDOWS || THERON_BOOST || THERON_CPP11 83 | 84 | uint32_t backoff(0); 85 | while (true) 86 | { 87 | uint32_t currentValue(UNLOCKED); 88 | if (mValue.CompareExchangeAcquire(currentValue, LOCKED)) 89 | { 90 | return; 91 | } 92 | 93 | Utils::Backoff(backoff); 94 | } 95 | 96 | #elif THERON_POSIX 97 | 98 | pthread_spin_lock(&mSpinLock); 99 | 100 | #endif 101 | } 102 | 103 | /** 104 | Unlocks the spinlock. 105 | Unlocking the spinlock releases exclusive access previously acquired with Lock. 106 | */ 107 | THERON_FORCEINLINE void Unlock() 108 | { 109 | #if THERON_WINDOWS || THERON_BOOST || THERON_CPP11 110 | 111 | THERON_ASSERT(mValue.Load() == LOCKED); 112 | mValue.Store(UNLOCKED); 113 | 114 | #elif THERON_POSIX 115 | 116 | pthread_spin_unlock(&mSpinLock); 117 | 118 | #endif 119 | } 120 | 121 | private: 122 | 123 | SpinLock(const SpinLock &other); 124 | SpinLock &operator=(const SpinLock &other); 125 | 126 | #if THERON_WINDOWS || THERON_BOOST || THERON_CPP11 127 | 128 | static const uint32_t UNLOCKED = 0; 129 | static const uint32_t LOCKED = 1; 130 | 131 | Atomic::UInt32 mValue; 132 | 133 | #elif THERON_POSIX 134 | 135 | pthread_spinlock_t mSpinLock; 136 | 137 | #endif 138 | 139 | } THERON_POSTALIGN(THERON_CACHELINE_ALIGNMENT); 140 | 141 | 142 | } // namespace Detail 143 | } // namespace Theron 144 | 145 | 146 | #ifdef _MSC_VER 147 | #pragma warning(pop) 148 | #endif //_MSC_VER 149 | 150 | 151 | #endif // THERON_DETAIL_THREADING_SPINLOCK_H 152 | -------------------------------------------------------------------------------- /Include/Theron/Detail/Transport/Context.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) by Ashton Mason. See LICENSE.txt for licensing information. 2 | #ifndef THERON_DETAIL_TRANSPORT_CONTEXT_H 3 | #define THERON_DETAIL_TRANSPORT_CONTEXT_H 4 | 5 | 6 | #include 7 | 8 | // NOTE: Must include xs.h before standard headers to avoid warnings in MS headers! 9 | #if THERON_XS 10 | #include 11 | #endif // THERON_XS 12 | 13 | #include 14 | #include 15 | 16 | 17 | namespace Theron 18 | { 19 | namespace Detail 20 | { 21 | 22 | 23 | class InputSocket; 24 | class OutputSocket; 25 | 26 | 27 | /** 28 | \brief Network context wrapper. 29 | 30 | Currently implemented with Crossroads.io (libxs). 31 | */ 32 | class Context 33 | { 34 | public: 35 | 36 | friend class InputSocket; 37 | friend class OutputSocket; 38 | 39 | /** 40 | \brief Default constructor. 41 | Constructs a network context. At most one network context is created per application. 42 | */ 43 | inline Context() 44 | { 45 | #if THERON_XS 46 | 47 | // Create XS context. 48 | mContext = xs_init(); 49 | if (mContext == 0) 50 | { 51 | THERON_FAIL_MSG("Failed to initialize XS context"); 52 | } 53 | 54 | #endif // THERON_XS 55 | } 56 | 57 | /** 58 | \brief Destructor. 59 | Destructs a network context. 60 | */ 61 | inline ~Context() 62 | { 63 | #if THERON_XS 64 | 65 | // Destroy the XS context. 66 | if (xs_term(mContext) != 0) 67 | { 68 | THERON_FAIL_MSG("Failed to terminate XS context"); 69 | } 70 | 71 | #endif // THERON_XS 72 | } 73 | 74 | /** 75 | \brief Returns true if network support is enabled. 76 | This is used to catch the case where network support is not enabled. 77 | */ 78 | inline bool Enabled() const 79 | { 80 | #if THERON_XS 81 | 82 | return (mContext != 0); 83 | 84 | #else 85 | 86 | return false; 87 | 88 | #endif // THERON_XS 89 | } 90 | 91 | private: 92 | 93 | #if THERON_XS 94 | void *mContext; ///< Void pointer to an XS context. 95 | #endif // THERON_XS 96 | 97 | }; 98 | 99 | 100 | } // namespace Detail 101 | } // namespace Theron 102 | 103 | 104 | #endif // THERON_DETAIL_TRANSPORT_CONTEXT_H 105 | -------------------------------------------------------------------------------- /Include/Theron/Detail/Transport/InputMessage.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) by Ashton Mason. See LICENSE.txt for licensing information. 2 | #ifndef THERON_DETAIL_TRANSPORT_INPUTMESSAGE_H 3 | #define THERON_DETAIL_TRANSPORT_INPUTMESSAGE_H 4 | 5 | 6 | #include 7 | 8 | // NOTE: Must include xs.h before standard headers to avoid warnings in MS headers! 9 | #if THERON_XS 10 | #include 11 | #endif // THERON_XS 12 | 13 | #include 14 | #include 15 | 16 | #include 17 | 18 | 19 | namespace Theron 20 | { 21 | namespace Detail 22 | { 23 | 24 | 25 | class InputSocket; 26 | 27 | 28 | /** 29 | \brief Network input message wrapper. 30 | 31 | Currently implemented with Crossroads.io (libxs). 32 | */ 33 | class InputMessage 34 | { 35 | public: 36 | 37 | friend class InputSocket; 38 | 39 | /** 40 | \brief Constructor. 41 | Constructs an input message for use with the given network context. 42 | An input message can be used to hold message data read from an InputSocket. 43 | */ 44 | inline explicit InputMessage(Context *const /*context*/) 45 | { 46 | } 47 | 48 | /** 49 | \brief Initializes an InputMessage. 50 | An InputMessage must be initialized before use. 51 | \return True, if the message was initialized without error. 52 | \note A single InputMessage can be reused multiple times by repeatedly calling Initialize and Release. 53 | */ 54 | inline bool Initialize() 55 | { 56 | #if THERON_XS 57 | 58 | // Initialize the XS message. 59 | if (xs_msg_init(&mMessage) == 0) 60 | { 61 | return true; 62 | } 63 | 64 | #endif // THERON_XS 65 | 66 | return false; 67 | } 68 | 69 | /** 70 | \brief Releases data held by an InputMessage. 71 | An InputMessage must be released after use and prior to destruction. 72 | \return True, if the message was released without error. 73 | \note A single InputMessage can be reused multiple times by repeatedly calling Initialize and Release. 74 | */ 75 | inline bool Release() 76 | { 77 | #if THERON_XS 78 | 79 | // Close the XS message. 80 | if (xs_msg_close(&mMessage) == 0) 81 | { 82 | return true; 83 | } 84 | 85 | #endif // THERON_XS 86 | 87 | return false; 88 | } 89 | 90 | /** 91 | \brief Returns the size of the message data held in an InputMessage. 92 | Call this method after reading a message from an InputSocket using InputSocket::NonBlockingReceive. 93 | \return The size of the read message data in bytes. 94 | */ 95 | inline uint32_t Size() 96 | { 97 | uint32_t size(0); 98 | 99 | #if THERON_XS 100 | 101 | size = static_cast(xs_msg_size(&mMessage)); 102 | 103 | #endif // THERON_XS 104 | 105 | return size; 106 | } 107 | 108 | /** 109 | \brief Returns a pointer to the message data held in an InputMessage. 110 | Call this method after reading a message from an InputSocket using InputSocket::NonBlockingReceive. 111 | */ 112 | inline void *Data() 113 | { 114 | void *data(0); 115 | 116 | #if THERON_XS 117 | 118 | data = xs_msg_data(&mMessage); 119 | 120 | #endif // THERON_XS 121 | 122 | return data; 123 | } 124 | 125 | private: 126 | 127 | #if THERON_XS 128 | xs_msg_t mMessage; ///< XS message. 129 | #endif // THERON_XS 130 | 131 | }; 132 | 133 | 134 | } // namespace Detail 135 | } // namespace Theron 136 | 137 | 138 | #endif // THERON_DETAIL_TRANSPORT_INPUTMESSAGE_H 139 | -------------------------------------------------------------------------------- /Include/Theron/Detail/Transport/InputSocket.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) by Ashton Mason. See LICENSE.txt for licensing information. 2 | #ifndef THERON_DETAIL_TRANSPORT_INPUTSOCKET_H 3 | #define THERON_DETAIL_TRANSPORT_INPUTSOCKET_H 4 | 5 | 6 | #include 7 | 8 | // NOTE: Must include xs.h before standard headers to avoid warnings in MS headers! 9 | #if THERON_XS 10 | #include 11 | #endif // THERON_XS 12 | 13 | #include 14 | #include 15 | 16 | #include 17 | 18 | 19 | namespace Theron 20 | { 21 | namespace Detail 22 | { 23 | 24 | 25 | /** 26 | \brief Network input socket wrapper. 27 | 28 | Currently implemented with Crossroads.io (libxs). 29 | */ 30 | class InputSocket 31 | { 32 | public: 33 | 34 | /** 35 | \brief Constructs a new input socket within the given network context. 36 | */ 37 | inline explicit InputSocket(Context *const context) 38 | { 39 | (void) context; 40 | 41 | #if THERON_XS 42 | 43 | mSocket = xs_socket(context->mContext, XS_SUB); 44 | if (mSocket == 0) 45 | { 46 | THERON_FAIL_MSG("Failed to create XS subscribe socket"); 47 | } 48 | 49 | // TODO: We could be smart and only subscribe to messages we care about. 50 | // Set a null subscribe filter on the subscribe socket so it receives all published messages. 51 | // This must be done before the socket is connected. 52 | if (xs_setsockopt(mSocket, XS_SUBSCRIBE, "", 0) != 0) 53 | { 54 | THERON_FAIL_MSG("Failed to set XS socket subscribe option"); 55 | } 56 | 57 | #endif // THERON_XS 58 | } 59 | 60 | /** 61 | \brief Destructs an InputSocket. 62 | */ 63 | inline ~InputSocket() 64 | { 65 | #if THERON_XS 66 | 67 | THERON_ASSERT(mSocket); 68 | 69 | // Close the XS socket. 70 | if (xs_close(mSocket) != 0) 71 | { 72 | THERON_FAIL_MSG("Failed to close XS subscribe socket"); 73 | } 74 | 75 | #endif // THERON_XS 76 | } 77 | 78 | /** 79 | \brief Connects an InputSocket socket to a remote endpoint. 80 | The input socket is implicitly connected to any OutputSocket instances bound locally to the remote endpoint. 81 | \param location A string identifying the remote endpoint, currently in XS format. 82 | \return True if the connection request was successfully created. 83 | \note The return value of this function doesn't imply that the connection will actually be made, merely that it was requested. 84 | */ 85 | inline bool Connect(const char *const location) 86 | { 87 | (void) location; 88 | 89 | #if THERON_XS 90 | 91 | THERON_ASSERT(mSocket); 92 | 93 | // Connect the subscribe socket to the remote host. 94 | // The same socket can be connected to multiple remote endpoints. 95 | if (xs_connect(mSocket, location) != -1) 96 | { 97 | return true; 98 | } 99 | 100 | #endif // THERON_XS 101 | 102 | return false; 103 | } 104 | 105 | /** 106 | \brief Tries to receive a message into the given InputMessage, without blocking. 107 | This method reads the first available message from the socket into the given InputMessage. 108 | This method is a non-blocking call and doesn't block or what for a message to arrive. 109 | \param inputMessage Pointer to an InputMessage to be filled with the read message data. 110 | \return True, if a message was available and successfully read. 111 | */ 112 | inline bool NonBlockingReceive(InputMessage *const inputMessage) 113 | { 114 | (void) inputMessage; 115 | 116 | #if THERON_XS 117 | 118 | // Send the network message. 119 | if (xs_recvmsg(mSocket, &inputMessage->mMessage, XS_DONTWAIT) != -1) 120 | { 121 | return true; 122 | } 123 | 124 | #endif // THERON_XS 125 | 126 | return false; 127 | } 128 | 129 | private: 130 | 131 | #if THERON_XS 132 | void *mSocket; ///< Void pointer to an XS socket. 133 | #endif // THERON_XS 134 | 135 | }; 136 | 137 | 138 | } // namespace Detail 139 | } // namespace Theron 140 | 141 | 142 | #endif // THERON_DETAIL_TRANSPORT_INPUTSOCKET_H 143 | -------------------------------------------------------------------------------- /Include/Theron/Detail/Transport/OutputMessage.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) by Ashton Mason. See LICENSE.txt for licensing information. 2 | #ifndef THERON_DETAIL_TRANSPORT_OUTPUTMESSAGE_H 3 | #define THERON_DETAIL_TRANSPORT_OUTPUTMESSAGE_H 4 | 5 | 6 | #include 7 | 8 | // NOTE: Must include xs.h before standard headers to avoid warnings in MS headers! 9 | #if THERON_XS 10 | #include 11 | #endif // THERON_XS 12 | 13 | #include 14 | #include 15 | 16 | #include 17 | 18 | 19 | namespace Theron 20 | { 21 | namespace Detail 22 | { 23 | 24 | 25 | class OutputSocket; 26 | 27 | 28 | /** 29 | \brief Network output message wrapper. 30 | 31 | Currently implemented with Crossroads.io (libxs). 32 | */ 33 | class OutputMessage 34 | { 35 | public: 36 | 37 | friend class OutputSocket; 38 | 39 | /** 40 | \brief Constructor. 41 | Constructs an output message for use with the given network context. 42 | An output message can be used to hold message data written to an OutputSocket. 43 | */ 44 | inline explicit OutputMessage(Context *const /*context*/) 45 | { 46 | } 47 | 48 | /** 49 | \brief Initializes an OutputMessage. 50 | An OutputMessage must be initialized before use. 51 | \param size The size of the message data to be written, in bytes. 52 | \return True, if the message was initialized without error. 53 | \note A single OutputMessage can be reused multiple times by repeatedly calling Initialize and Release. 54 | */ 55 | inline bool Initialize(const uint32_t size) 56 | { 57 | (void) size; 58 | 59 | #if THERON_XS 60 | 61 | // Initialize the XS message. 62 | if (xs_msg_init_size(&mMessage, size) == 0) 63 | { 64 | return true; 65 | } 66 | 67 | #endif // THERON_XS 68 | 69 | return false; 70 | } 71 | 72 | /** 73 | \brief Releases data held by an OutputMessage. 74 | An OutputMessage must be released after use and prior to destruction. 75 | \return True, if the message was released without error. 76 | \note A single OutputMessage can be reused multiple times by repeatedly calling Initialize and Release. 77 | */ 78 | inline bool Release() 79 | { 80 | #if THERON_XS 81 | 82 | // Close the XS message. 83 | if (xs_msg_close(&mMessage) == 0) 84 | { 85 | return true; 86 | } 87 | 88 | #endif // THERON_XS 89 | 90 | return false; 91 | } 92 | 93 | /** 94 | \brief Returns a pointer to the message data held in an OutputMessage. 95 | Call this method before writing a message to an OutputSocket using OutputSocket::Send. 96 | After acquiring a pointer to the data block the caller can write the message data into it. 97 | \return A void pointer to the data block owned by the message. 98 | */ 99 | inline void *Data() 100 | { 101 | void *data(0); 102 | 103 | #if THERON_XS 104 | 105 | data = xs_msg_data(&mMessage); 106 | 107 | #endif // THERON_XS 108 | 109 | return data; 110 | } 111 | 112 | private: 113 | 114 | #if THERON_XS 115 | xs_msg_t mMessage; ///< XS message. 116 | #endif // THERON_XS 117 | 118 | }; 119 | 120 | 121 | } // namespace Detail 122 | } // namespace Theron 123 | 124 | 125 | #endif // THERON_DETAIL_TRANSPORT_OUTPUTMESSAGE_H 126 | -------------------------------------------------------------------------------- /Include/Theron/Detail/Transport/OutputSocket.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) by Ashton Mason. See LICENSE.txt for licensing information. 2 | #ifndef THERON_DETAIL_TRANSPORT_OUTPUTSOCKET_H 3 | #define THERON_DETAIL_TRANSPORT_OUTPUTSOCKET_H 4 | 5 | 6 | #include 7 | 8 | // NOTE: Must include xs.h before standard headers to avoid warnings in MS headers! 9 | #if THERON_XS 10 | #include 11 | #endif // THERON_XS 12 | 13 | #include 14 | #include 15 | 16 | #include 17 | #include 18 | 19 | 20 | namespace Theron 21 | { 22 | namespace Detail 23 | { 24 | 25 | 26 | /** 27 | \brief Network output socket wrapper. 28 | 29 | Currently implemented with Crossroads.io (libxs). 30 | */ 31 | class OutputSocket 32 | { 33 | public: 34 | 35 | /** 36 | \brief Constructs a new output socket within the given network context. 37 | */ 38 | inline explicit OutputSocket(Context *const context) 39 | { 40 | (void) context; 41 | 42 | #if THERON_XS 43 | 44 | mSocket = xs_socket(context->mContext, XS_PUB); 45 | if (mSocket == 0) 46 | { 47 | THERON_FAIL_MSG("Failed to create XS publish socket"); 48 | } 49 | 50 | #endif // THERON_XS 51 | } 52 | 53 | /** 54 | \brief Destructs an OutputSocket. 55 | */ 56 | inline ~OutputSocket() 57 | { 58 | #if THERON_XS 59 | 60 | THERON_ASSERT(mSocket); 61 | 62 | // Close the XS socket. 63 | if (xs_close(mSocket) != 0) 64 | { 65 | THERON_FAIL_MSG("Failed to close XS publish socket"); 66 | } 67 | 68 | #endif // THERON_XS 69 | } 70 | 71 | /** 72 | \brief Binds an OutputSocket socket to a local endpoint. 73 | The output socket is implicitly connected to any remote InputSocket instances bound to the local endpoint. 74 | \param location A string identifying the local endpoint, currently in XS format. 75 | \return True, if the socket was bound without error. 76 | */ 77 | inline bool Bind(const char *const location) 78 | { 79 | (void) location; 80 | 81 | #if THERON_XS 82 | 83 | THERON_ASSERT(mSocket); 84 | 85 | if (xs_bind(mSocket, location) != -1) 86 | { 87 | return true; 88 | } 89 | 90 | #endif // THERON_XS 91 | 92 | return false; 93 | } 94 | 95 | /** 96 | \brief Sends a message contained in the given InputMessage. 97 | This method sends the given message data in the given OutputMessage on the OutputSocket. 98 | \param outputMessage Pointer to an OutputMessage containing the message data to be sent. 99 | \return True, if the message was sent without error. 100 | \note Just because the message was sent on the OutputSocket doesn't imply that it was read 101 | and processed by a InputSocket connected to the endpoint to which the OutputSocket is bound. 102 | */ 103 | inline bool Send(OutputMessage *const outputMessage) 104 | { 105 | (void) outputMessage; 106 | 107 | #if THERON_XS 108 | 109 | // Send the network message. 110 | if (xs_sendmsg(mSocket, &outputMessage->mMessage, 0) >= 0) 111 | { 112 | return true; 113 | } 114 | 115 | #endif // THERON_XS 116 | 117 | return false; 118 | } 119 | 120 | private: 121 | 122 | #if THERON_XS 123 | void *mSocket; ///< Void pointer to an XS socket. 124 | #endif // THERON_XS 125 | 126 | }; 127 | 128 | 129 | } // namespace Detail 130 | } // namespace Theron 131 | 132 | 133 | #endif // THERON_DETAIL_TRANSPORT_OUTPUTSOCKET_H 134 | -------------------------------------------------------------------------------- /Include/Theron/IAllocator.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) by Ashton Mason. See LICENSE.txt for licensing information. 2 | #ifndef THERON_IALLOCATOR_H 3 | #define THERON_IALLOCATOR_H 4 | 5 | 6 | /** 7 | \file IAllocator.h 8 | Allocator interface. 9 | */ 10 | 11 | 12 | #include 13 | 14 | 15 | namespace Theron 16 | { 17 | 18 | 19 | /** 20 | \brief Interface describing a general-purpose memory allocator. 21 | 22 | This interface class defines the interface expected of allocators used by Theron. 23 | In particular, it characterizes the type of allocator that can be assigned as 24 | Theron's internal allocator with \ref AllocatorManager::SetAllocator. 25 | 26 | By implementing the IAllocator interface on a custom allocator implementation 27 | (or wrapping an existing allocator in a custom wrapper that implements IAllocator), 28 | users can provide a custom allocator to be used by Theron. When set via 29 | \ref AllocatorManager::SetAllocator, then the allocator replaces the \ref 30 | DefaultAllocator that is used within Theron by default. 31 | 32 | By replacing the default allocator, users can control, cache, or optimize the 33 | allocation of memory within Theron. Theron guarantees that all of its internal 34 | heap allocations are allocated via the allocator set with 35 | \ref AllocatorManager::SetAllocator, as long as the allocator is set before 36 | any Theron objects are constructed. 37 | */ 38 | class IAllocator 39 | { 40 | public: 41 | 42 | /** 43 | \brief Defines an integer type used for specifying sizes of memory allocations. 44 | */ 45 | typedef uint32_t SizeType; 46 | 47 | /** 48 | \brief Default constructor 49 | */ 50 | inline IAllocator() 51 | { 52 | } 53 | 54 | /** 55 | \brief Virtual destructor 56 | */ 57 | inline virtual ~IAllocator() 58 | { 59 | } 60 | 61 | /** 62 | \brief Allocates a piece of contiguous memory. 63 | \param size The size of the memory to allocate, in bytes. 64 | \return A pointer to the allocated memory. 65 | */ 66 | virtual void *Allocate(const SizeType size) = 0; 67 | 68 | /** 69 | \brief Allocates a piece of contiguous memory aligned to a given byte-multiple boundary. 70 | \param size The size of the memory to allocate, in bytes. 71 | \param alignment The alignment of the memory to allocate, in bytes. 72 | \return A pointer to the allocated memory. 73 | \note The default implementation, which implementors can override, 74 | simply calls \ref Allocate, ignoring the alignment. This provides backwards 75 | compatibility with legacy implementations that don't implement AllocateAligned. 76 | */ 77 | inline virtual void *AllocateAligned(const SizeType size, const SizeType /*alignment*/) 78 | { 79 | return Allocate(size); 80 | } 81 | 82 | /** 83 | \brief Frees a previously allocated piece of contiguous memory. 84 | \param memory A pointer to the memory to be deallocated. 85 | */ 86 | virtual void Free(void *const memory) = 0; 87 | 88 | /** 89 | \brief Frees a previously allocated block of contiguous memory of a known size. 90 | Knowing the size of the freed block allows some implementations to cache and reuse freed blocks. 91 | \param memory A pointer to the block of memory to be deallocated. 92 | \param size The size of the freed block. 93 | \note The default implementation, which implementors can override, 94 | simply calls \ref Free with no size, ignoring the size parameter. This provides backwards 95 | compatibility with legacy implementations that don't implement this overload of Free. 96 | */ 97 | inline virtual void Free(void *const memory, const SizeType /*size*/) 98 | { 99 | Free(memory); 100 | } 101 | 102 | private: 103 | 104 | IAllocator(const IAllocator &other); 105 | IAllocator &operator=(const IAllocator &other); 106 | }; 107 | 108 | 109 | } // namespace Theron 110 | 111 | 112 | #endif // THERON_IALLOCATOR_H 113 | -------------------------------------------------------------------------------- /Include/Theron/Theron.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) by Ashton Mason. See LICENSE.txt for licensing information. 2 | #ifndef THERON_THERON_H 3 | #define THERON_THERON_H 4 | 5 | 6 | /** 7 | \file Theron.h 8 | All-inclusive wrapper header that includes all public headers. 9 | */ 10 | 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | 28 | 29 | #endif // THERON_THERON_H 30 | -------------------------------------------------------------------------------- /Lib/README.txt: -------------------------------------------------------------------------------- 1 | Theron libraries are built to this folder. 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | theron 2 | ====== 3 | 4 | Main Theron release line -------------------------------------------------------------------------------- /README.txt: -------------------------------------------------------------------------------- 1 | 2 | Welcome to Theron! 3 | 4 | Please see the included file LICENSE.txt for licensing information. 5 | 6 | See the included HTML documentation in the /Docs folder for more information. 7 | If the documentation is missing from your distribution, you can find it online 8 | at http://www.theron-library.com 9 | 10 | If you have any questions, feedback or bug reports, please send them to 11 | me at ash@ashtonmason.net 12 | 13 | Ashton Mason 14 | -------------------------------------------------------------------------------- /Tests/TestFramework/ITestSuite.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) by Ashton Mason. See LICENSE.txt for licensing information. 2 | 3 | 4 | #ifndef TESTFRAMEWORK_ITESTSUITE_H 5 | #define TESTFRAMEWORK_ITESTSUITE_H 6 | 7 | 8 | #ifdef _MSC_VER 9 | #pragma warning(push,0) 10 | #pragma warning (disable:4530) // C++ exception handler used, but unwind semantics are not enabled 11 | #endif //_MSC_VER 12 | 13 | #include 14 | #include 15 | 16 | #ifdef _MSC_VER 17 | #pragma warning(pop) 18 | #endif //_MSC_VER 19 | 20 | 21 | namespace TestFramework 22 | { 23 | 24 | 25 | /// Interface describing a suite of unit tests. 26 | class ITestSuite 27 | { 28 | public: 29 | 30 | /// Defines a test suite name. 31 | typedef std::string TestSuiteName; 32 | 33 | /// Defines a test name. 34 | typedef std::string TestName; 35 | 36 | /// Defines a static test method. 37 | /// Static member functions count as static functions and can be used as tests. 38 | typedef void (*Test)(); 39 | 40 | /// Defines a list of tests in a test suite. 41 | typedef std::vector TestList; 42 | 43 | /// Defines a list of test names. 44 | typedef std::vector TestNameList; 45 | 46 | /// Defines a test error message. 47 | typedef std::string Error; 48 | 49 | /// Defines a list of test error messages. 50 | typedef std::vector ErrorList; 51 | 52 | /// Default constructor 53 | inline ITestSuite() 54 | { 55 | } 56 | 57 | /// Virtual destructor 58 | inline virtual ~ITestSuite() 59 | { 60 | } 61 | 62 | /// Runs all tests in the suite. 63 | /// \return True, if all the tests in the suite passed. 64 | virtual bool RunTests(const bool verbose) = 0; 65 | 66 | /// Gets the errors returned by the failed tests in the suite. 67 | /// \return A list of errors. 68 | virtual const ErrorList &GetErrors() = 0; 69 | 70 | private: 71 | 72 | /// Disallowed copy constructor. TestSuite objects can't be copied. 73 | ITestSuite(const ITestSuite &other); 74 | /// Disallowed assignment operator. ITestSuite objects can't be assigned. 75 | ITestSuite &operator=(const ITestSuite &other); 76 | }; 77 | 78 | 79 | } // namespace TestFramework 80 | 81 | 82 | #endif // TESTFRAMEWORK_ITESTSUITE_H 83 | 84 | -------------------------------------------------------------------------------- /Tests/TestFramework/TestException.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) by Ashton Mason. See LICENSE.txt for licensing information. 2 | 3 | 4 | #ifndef TESTFRAMEWORK_TESTEXCEPTION_H 5 | #define TESTFRAMEWORK_TESTEXCEPTION_H 6 | 7 | 8 | #ifdef _MSC_VER 9 | #pragma warning(push,0) 10 | #pragma warning (disable:4530) // C++ exception handler used, but unwind semantics are not enabled 11 | #endif //_MSC_VER 12 | 13 | #include 14 | 15 | #ifdef _MSC_VER 16 | #pragma warning(pop) 17 | #endif //_MSC_VER 18 | 19 | 20 | namespace TestFramework 21 | { 22 | 23 | 24 | /// Simple exception type for use in unit tests. 25 | class TestException 26 | { 27 | public: 28 | 29 | /// Constructor. 30 | /// \param msg A string message associated with the exception. 31 | explicit TestException(const std::string &msg) : mMsg(msg) 32 | { 33 | } 34 | 35 | /// Virtual destructor. 36 | virtual ~TestException() 37 | { 38 | } 39 | 40 | const std::string &GetMessage() 41 | { 42 | return mMsg; 43 | } 44 | 45 | private: 46 | 47 | /// Disallowed default constructor 48 | TestException() { } 49 | 50 | /// Disallowed copy constructor. 51 | TestException(const TestException &other); 52 | /// Disallowed assignment operator. 53 | TestException &operator=(const TestException &other); 54 | 55 | /// Message associated with the exception. 56 | std::string mMsg; 57 | }; 58 | 59 | 60 | } // namespace TestFramework 61 | 62 | 63 | #endif // TESTFRAMEWORK_TESTEXCEPTION_H 64 | 65 | -------------------------------------------------------------------------------- /Tests/TestFramework/TestManager.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) by Ashton Mason. See LICENSE.txt for licensing information. 2 | 3 | 4 | #ifndef TESTFRAMEWORK_TESTMANAGER_H 5 | #define TESTFRAMEWORK_TESTMANAGER_H 6 | 7 | 8 | #ifdef _MSC_VER 9 | #pragma warning(push,0) 10 | #pragma warning (disable:4530) // C++ exception handler used, but unwind semantics are not enabled 11 | #endif //_MSC_VER 12 | 13 | #include 14 | 15 | #ifdef _MSC_VER 16 | #pragma warning(pop) 17 | #endif //_MSC_VER 18 | 19 | #include "ITestSuite.h" 20 | 21 | 22 | namespace TestFramework 23 | { 24 | 25 | 26 | /// Singleton manager/factory class that manages a collection of unit tests suites. 27 | class TestManager 28 | { 29 | public: 30 | 31 | /// Defines a list of pointers to test suites. 32 | typedef std::vector TestSuiteList; 33 | 34 | /// Defines a test error message. 35 | typedef ITestSuite::Error Error; 36 | 37 | /// Defines a list of test error messages. 38 | typedef ITestSuite::ErrorList ErrorList; 39 | 40 | /// Destructor 41 | inline ~TestManager() 42 | { 43 | } 44 | 45 | /// Static method that returns a pointer to the single instance of the TestManager singleton. 46 | inline static TestManager *Instance() 47 | { 48 | static TestManager sInstance; 49 | return &sInstance; 50 | } 51 | 52 | /// Registers a test suite with the test suite manager. 53 | /// \param testSuite The test suite to be registered, which must implement ITestSuite. 54 | inline void Register(ITestSuite *const testSuite) 55 | { 56 | mTestSuites.push_back(testSuite); 57 | } 58 | 59 | /// Registers a test suite with the test suite manager. 60 | /// \return True if the test suites all passed, otherwise false. 61 | inline bool RunTests(const bool verbose) 62 | { 63 | mErrors.clear(); 64 | 65 | bool passedAllSuites = true; 66 | 67 | for (TestSuiteList::const_iterator it = mTestSuites.begin(); it != mTestSuites.end(); ++it) 68 | { 69 | ITestSuite *const testSuite = (*it); 70 | const bool passedSuite = testSuite->RunTests(verbose); 71 | 72 | if (!passedSuite) 73 | { 74 | // Collect the errors from the test suite. 75 | const ErrorList &suiteErrors(testSuite->GetErrors()); 76 | mErrors.insert(mErrors.end(), suiteErrors.begin(), suiteErrors.end()); 77 | passedAllSuites = false; 78 | } 79 | } 80 | 81 | return passedAllSuites; 82 | } 83 | 84 | /// Gets the errors returned by the failed tests in all registered test suites. 85 | /// \return A list of errors. 86 | inline const ErrorList &GetErrors() 87 | { 88 | return mErrors; 89 | } 90 | 91 | private: 92 | 93 | /// Private default constructor. This is a singleton class and can't be constructed directly. 94 | inline TestManager() 95 | { 96 | } 97 | 98 | /// Disallowed copy constructor. TestManager objects can't be copied. 99 | TestManager(const TestManager &other); 100 | /// Disallowed assignment operator. TestManager objects can't be assigned. 101 | TestManager &operator=(const TestManager &other); 102 | 103 | TestSuiteList mTestSuites; ///< List of test suites managed by the manager. 104 | ErrorList mErrors; ///< List of error messages returned by failed tests. 105 | }; 106 | 107 | 108 | } // namespace TestFramework 109 | 110 | 111 | #endif // TESTFRAMEWORK_TESTMANAGER_H 112 | 113 | -------------------------------------------------------------------------------- /Tests/Tests.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) by Ashton Mason. See LICENSE.txt for licensing information. 2 | 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #include 9 | 10 | #include "TestFramework/TestManager.h" 11 | 12 | #include "TestSuites/FeatureTestSuite.h" 13 | 14 | #if THERON_XS 15 | #include "TestSuites/NetworkTestSuite.h" 16 | #endif // THERON_XS 17 | 18 | 19 | /// Static instantiations of the test suites. 20 | Tests::FeatureTestSuite featureTestSuite; 21 | 22 | #if THERON_XS 23 | Tests::NetworkTestSuite networkTestSuite; 24 | #endif // THERON_XS 25 | 26 | 27 | int main(int argc, char *argv[]) 28 | { 29 | using namespace TestFramework; 30 | 31 | int count(1); 32 | bool verbose(false); 33 | 34 | int index(1); 35 | while (index < argc) 36 | { 37 | const char *const flag(argv[index]); 38 | 39 | if (strcmp(flag, "-count") == 0) 40 | { 41 | if (index + 1 < argc) 42 | { 43 | count = 0; 44 | count = atoi(argv[index + 1]); 45 | 46 | if (count) 47 | { 48 | ++index; 49 | } 50 | else 51 | { 52 | printf("ERROR: Unrecognized integer value after flag '%s'\n", flag); 53 | return 1; 54 | } 55 | } 56 | else 57 | { 58 | printf("ERROR: Expected integer value after flag '%s'\n", flag); 59 | return 1; 60 | } 61 | } 62 | else if (strcmp(flag, "-verbose") == 0) 63 | { 64 | verbose = true; 65 | } 66 | else 67 | { 68 | printf("ERROR: Unrecognized flag '%s'\n", flag); 69 | return 1; 70 | } 71 | 72 | ++index; 73 | } 74 | 75 | // Run all the tests, report the result, print any errors. 76 | bool allPassed(true); 77 | printf("Running tests %d time(s). Use -count to set count, -verbose to turn on output.\n", count); 78 | 79 | for (int iteration(0); iteration < count; ++iteration) 80 | { 81 | if (count > 1) 82 | { 83 | printf("Iteration %d ...\n", iteration); 84 | } 85 | 86 | allPassed = allPassed && TestManager::Instance()->RunTests(verbose); 87 | } 88 | 89 | if (!allPassed) 90 | { 91 | const TestManager::ErrorList &errors(TestManager::Instance()->GetErrors()); 92 | printf("Tests FAILED with %d error%s\n", static_cast(errors.size()), errors.size() == 1 ? "" : "s"); 93 | return 1; 94 | } 95 | 96 | printf("PASSED\n"); 97 | return 0; 98 | } 99 | 100 | 101 | -------------------------------------------------------------------------------- /Tests/Tests.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hpp;hxx;hm;inl;inc;xsd 11 | 12 | 13 | {77f5c9b4-af07-4f1b-883d-6e2a8113013c} 14 | 15 | 16 | {470cdaa3-3820-40f3-bcb8-fe76b0d2f4bd} 17 | 18 | 19 | 20 | 21 | Header Files\TestSuites 22 | 23 | 24 | Header Files\TestFramework 25 | 26 | 27 | Header Files\TestFramework 28 | 29 | 30 | Header Files\TestFramework 31 | 32 | 33 | Header Files\TestFramework 34 | 35 | 36 | Header Files\TestSuites 37 | 38 | 39 | 40 | 41 | Source Files 42 | 43 | 44 | -------------------------------------------------------------------------------- /Theron/Actor.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) by Ashton Mason. See LICENSE.txt for licensing information. 2 | 3 | 4 | #include 5 | #include 6 | 7 | 8 | namespace Theron 9 | { 10 | 11 | 12 | Actor::Actor(Framework &framework, const char *const name) : 13 | mAddress(), 14 | mFramework(&framework), 15 | mMessageHandlers(), 16 | mDefaultHandlers(), 17 | mMailboxContext(0), 18 | mMemory(0) 19 | { 20 | // Claim an available directory index and mailbox for this actor. 21 | mFramework->RegisterActor(this, name); 22 | } 23 | 24 | 25 | Actor::~Actor() 26 | { 27 | mFramework->DeregisterActor(this); 28 | } 29 | 30 | 31 | void Actor::Fallback( 32 | Detail::FallbackHandlerCollection *const fallbackHandlers, 33 | const Detail::IMessage *const message) 34 | { 35 | // If default handlers are registered with this actor, execute those. 36 | if (mDefaultHandlers.Handle(this, message)) 37 | { 38 | return; 39 | } 40 | 41 | // Let the framework's fallback handlers handle the message. 42 | fallbackHandlers->Handle(message); 43 | } 44 | 45 | 46 | } // namespace Theron 47 | -------------------------------------------------------------------------------- /Theron/Address.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) by Ashton Mason. See LICENSE.txt for licensing information. 2 | 3 | 4 | #include 5 | 6 | 7 | namespace Theron 8 | { 9 | 10 | 11 | Address Address::smNullAddress; 12 | 13 | 14 | } // namespace Theron 15 | 16 | -------------------------------------------------------------------------------- /Theron/AllocatorManager.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) by Ashton Mason. See LICENSE.txt for licensing information. 2 | 3 | 4 | #include 5 | 6 | 7 | namespace Theron 8 | { 9 | 10 | 11 | DefaultAllocator AllocatorManager::smDefaultAllocator; 12 | AllocatorManager::CacheType AllocatorManager::smCache(&smDefaultAllocator); 13 | 14 | 15 | void AllocatorManager::SetAllocator(IAllocator *const allocator) 16 | { 17 | // This method should only be called once, at start of day. 18 | THERON_ASSERT_MSG(smDefaultAllocator.GetBytesAllocated() == 0, "SetAllocator can't be called while Theron objects are alive"); 19 | 20 | // We don't bother to make this thread-safe because it should only be called at start-of-day. 21 | if (allocator) 22 | { 23 | smCache.SetAllocator(allocator); 24 | } 25 | else 26 | { 27 | smCache.SetAllocator(&smDefaultAllocator); 28 | } 29 | } 30 | 31 | 32 | } // namespace Theron 33 | 34 | 35 | -------------------------------------------------------------------------------- /Theron/BuildDescriptor.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) by Ashton Mason. See LICENSE.txt for licensing information. 2 | 3 | 4 | #include 5 | #include 6 | 7 | #include 8 | 9 | 10 | #ifdef _MSC_VER 11 | #pragma warning(push) 12 | #pragma warning (disable:4996) // function or variable may be unsafe 13 | #pragma warning (disable:4127) // conditional expression is constant. 14 | #endif //_MSC_VER 15 | 16 | 17 | namespace Theron 18 | { 19 | namespace Detail 20 | { 21 | 22 | 23 | // This function must not be inlined because it should be generated in the Theron library. 24 | // NOTE: This must match the similar code in GenerateInline! 25 | THERON_NOINLINE void BuildDescriptor::GenerateInLibrary(char *const identifier) 26 | { 27 | char buffer[16]; 28 | 29 | THERON_ASSERT(identifier); 30 | 31 | // Build up a string identifier that characterizes the client build settings. 32 | strcpy(identifier, THERON_VERSION); 33 | 34 | if (THERON_64BIT) 35 | { 36 | strcat(identifier, ".64bit"); 37 | } 38 | else 39 | { 40 | strcat(identifier, ".32bit"); 41 | } 42 | 43 | sprintf(buffer, ".%dbytes", THERON_CACHELINE_ALIGNMENT); 44 | strcat(identifier, buffer); 45 | 46 | if (THERON_MSVC) 47 | { 48 | strcat(identifier, ".msvc"); 49 | } 50 | 51 | if (THERON_GCC) 52 | { 53 | strcat(identifier, ".gcc"); 54 | } 55 | 56 | if (THERON_DEBUG) 57 | { 58 | strcat(identifier, ".debug"); 59 | } 60 | 61 | if (THERON_BOOST) 62 | { 63 | strcat(identifier, ".boost"); 64 | } 65 | 66 | if (THERON_CPP11) 67 | { 68 | strcat(identifier, ".cpp11"); 69 | } 70 | 71 | if (THERON_POSIX) 72 | { 73 | strcat(identifier, ".posix"); 74 | } 75 | 76 | if (THERON_NUMA) 77 | { 78 | strcat(identifier, ".numa"); 79 | } 80 | 81 | if (THERON_XS) 82 | { 83 | strcat(identifier, ".xs"); 84 | } 85 | 86 | if (THERON_ENABLE_DEFAULTALLOCATOR_CHECKS) 87 | { 88 | strcat(identifier, ".alloc"); 89 | } 90 | 91 | if (THERON_ENABLE_MESSAGE_REGISTRATION_CHECKS) 92 | { 93 | strcat(identifier, ".register"); 94 | } 95 | 96 | if (THERON_ENABLE_UNHANDLED_MESSAGE_CHECKS) 97 | { 98 | strcat(identifier, ".unhandled"); 99 | } 100 | 101 | if (THERON_ENABLE_BUILD_CHECKS) 102 | { 103 | strcat(identifier, ".build"); 104 | } 105 | } 106 | 107 | 108 | } // namespace Detail 109 | } // namespace Theron 110 | 111 | 112 | #ifdef _MSC_VER 113 | #pragma warning(pop) 114 | #endif //_MSC_VER 115 | -------------------------------------------------------------------------------- /Theron/Clock.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) by Ashton Mason. See LICENSE.txt for licensing information. 2 | 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #include 9 | 10 | 11 | namespace Theron 12 | { 13 | namespace Detail 14 | { 15 | 16 | 17 | Clock::Static Clock::mStatic; 18 | 19 | 20 | Clock::Static::Static() : mTicksPerSecond(NANOSECONDS_PER_SECOND) 21 | { 22 | #if THERON_WINDOWS 23 | 24 | // The 'ticks' are cycles in the Windows implementation. 25 | LARGE_INTEGER counter; 26 | QueryPerformanceFrequency(&counter); 27 | mTicksPerSecond = (uint64_t) counter.QuadPart; 28 | 29 | #endif 30 | } 31 | 32 | 33 | } // namespace Detail 34 | } // namespace Theron 35 | 36 | 37 | -------------------------------------------------------------------------------- /Theron/DefaultHandlerCollection.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) by Ashton Mason. See LICENSE.txt for licensing information. 2 | 3 | 4 | #include 5 | 6 | 7 | namespace Theron 8 | { 9 | namespace Detail 10 | { 11 | 12 | 13 | DefaultHandlerCollection::DefaultHandlerCollection() : 14 | mHandler(0), 15 | mNewHandler(0), 16 | mHandlersDirty(false) 17 | { 18 | } 19 | 20 | 21 | DefaultHandlerCollection::~DefaultHandlerCollection() 22 | { 23 | Clear(); 24 | } 25 | 26 | 27 | bool DefaultHandlerCollection::Clear() 28 | { 29 | IAllocator *const allocator(AllocatorManager::GetCache()); 30 | 31 | // Destroy any currently set handlers. 32 | if (mHandler) 33 | { 34 | mHandler->~IDefaultHandler(); 35 | allocator->Free(mHandler); 36 | mHandler = 0; 37 | } 38 | 39 | if (mNewHandler) 40 | { 41 | mNewHandler->~IDefaultHandler(); 42 | allocator->Free(mNewHandler); 43 | mNewHandler = 0; 44 | } 45 | 46 | mHandlersDirty = false; 47 | return true; 48 | } 49 | 50 | 51 | bool DefaultHandlerCollection::Handle(Actor *const actor, const IMessage *const message) 52 | { 53 | bool handled(false); 54 | 55 | THERON_ASSERT(actor); 56 | THERON_ASSERT(message); 57 | 58 | // Update the handler list if there have been changes. 59 | if (mHandlersDirty) 60 | { 61 | UpdateHandlers(); 62 | } 63 | 64 | if (mHandler) 65 | { 66 | mHandler->Handle(actor, message); 67 | handled = true; 68 | } 69 | 70 | return handled; 71 | } 72 | 73 | 74 | void DefaultHandlerCollection::UpdateHandlers() 75 | { 76 | IAllocator *const allocator(AllocatorManager::GetCache()); 77 | 78 | mHandlersDirty = false; 79 | 80 | // Destroy any currently set handler. 81 | if (mHandler) 82 | { 83 | mHandler->~IDefaultHandler(); 84 | allocator->Free(mHandler); 85 | mHandler = 0; 86 | } 87 | 88 | // Make the new handler (if any) the current handler. 89 | mHandler = mNewHandler; 90 | mNewHandler = 0; 91 | } 92 | 93 | 94 | } // namespace Detail 95 | } // namespace Theron 96 | 97 | 98 | -------------------------------------------------------------------------------- /Theron/FallbackHandlerCollection.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) by Ashton Mason. See LICENSE.txt for licensing information. 2 | 3 | 4 | #include 5 | 6 | 7 | namespace Theron 8 | { 9 | namespace Detail 10 | { 11 | 12 | 13 | FallbackHandlerCollection::FallbackHandlerCollection() : 14 | mHandler(0), 15 | mNewHandler(0), 16 | mHandlersDirty(false) 17 | { 18 | } 19 | 20 | 21 | FallbackHandlerCollection::~FallbackHandlerCollection() 22 | { 23 | Clear(); 24 | } 25 | 26 | 27 | bool FallbackHandlerCollection::Clear() 28 | { 29 | IAllocator *const allocator(AllocatorManager::GetCache()); 30 | 31 | // Destroy any currently set handlers. 32 | if (mHandler) 33 | { 34 | mHandler->~IFallbackHandler(); 35 | allocator->Free(mHandler); 36 | mHandler = 0; 37 | } 38 | 39 | if (mNewHandler) 40 | { 41 | mNewHandler->~IFallbackHandler(); 42 | allocator->Free(mNewHandler); 43 | mNewHandler = 0; 44 | } 45 | 46 | mHandlersDirty = false; 47 | return true; 48 | } 49 | 50 | 51 | bool FallbackHandlerCollection::Handle(const IMessage *const message) 52 | { 53 | bool handled(false); 54 | 55 | THERON_ASSERT(message); 56 | 57 | // Update the handler list if there have been changes. 58 | if (mHandlersDirty) 59 | { 60 | UpdateHandlers(); 61 | } 62 | 63 | if (mHandler) 64 | { 65 | mHandler->Handle(message); 66 | handled = true; 67 | } 68 | 69 | return handled; 70 | } 71 | 72 | 73 | void FallbackHandlerCollection::UpdateHandlers() 74 | { 75 | IAllocator *const allocator(AllocatorManager::GetCache()); 76 | 77 | mHandlersDirty = false; 78 | 79 | // Destroy any currently set handler. 80 | if (mHandler) 81 | { 82 | mHandler->~IFallbackHandler(); 83 | allocator->Free(mHandler); 84 | mHandler = 0; 85 | } 86 | 87 | // Make the new handler (if any) the current handler. 88 | mHandler = mNewHandler; 89 | mNewHandler = 0; 90 | } 91 | 92 | 93 | } // namespace Detail 94 | } // namespace Theron 95 | 96 | 97 | -------------------------------------------------------------------------------- /Theron/HandlerCollection.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) by Ashton Mason. See LICENSE.txt for licensing information. 2 | 3 | 4 | #include 5 | 6 | 7 | namespace Theron 8 | { 9 | namespace Detail 10 | { 11 | 12 | 13 | HandlerCollection::HandlerCollection() : 14 | mHandlers(), 15 | mNewHandlers(), 16 | mHandlersDirty(false) 17 | { 18 | } 19 | 20 | 21 | HandlerCollection::~HandlerCollection() 22 | { 23 | Clear(); 24 | } 25 | 26 | 27 | void HandlerCollection::UpdateHandlers() 28 | { 29 | IAllocator *const allocator(AllocatorManager::GetCache()); 30 | 31 | mHandlersDirty = false; 32 | 33 | // Add any new handlers. We do this first in case any are already marked for deletion. 34 | // The handler class contains the next pointer, so handlers can only be in one list at a time. 35 | while (IMessageHandler *const handler = mNewHandlers.Front()) 36 | { 37 | mNewHandlers.Remove(handler); 38 | mHandlers.Insert(handler); 39 | } 40 | 41 | // Transfer all handlers to the new handler list, omitting any which are marked for deletion. 42 | while (IMessageHandler *const handler = mHandlers.Front()) 43 | { 44 | mHandlers.Remove(handler); 45 | if (handler->IsMarked()) 46 | { 47 | handler->~IMessageHandler(); 48 | allocator->Free(handler); 49 | } 50 | else 51 | { 52 | mNewHandlers.Insert(handler); 53 | } 54 | } 55 | 56 | // Finally transfer the filtered handlers back in the actual list. 57 | while (IMessageHandler *const handler = mNewHandlers.Front()) 58 | { 59 | mNewHandlers.Remove(handler); 60 | mHandlers.Insert(handler); 61 | } 62 | } 63 | 64 | 65 | } // namespace Detail 66 | } // namespace Theron 67 | 68 | 69 | -------------------------------------------------------------------------------- /Theron/Properties/Theron.props: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | $(SolutionDir)\Bin\ 7 | 8 | 9 | 10 | Level4 11 | 12 | 13 | 14 | 15 | true 16 | $(SolutionDir)\Include\External;$(SolutionDir)\Include\;%(AdditionalIncludeDirectories) 17 | _UNICODE;UNICODE;%(PreprocessorDefinitions) 18 | 19 | 20 | 21 | kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /Theron/Receiver.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) by Ashton Mason. See LICENSE.txt for licensing information. 2 | 3 | 4 | #include 5 | 6 | // Must include xs.h before standard headers to avoid warnings in MS headers! 7 | #if THERON_XS 8 | #include 9 | #endif // THERON_XS 10 | 11 | #include 12 | #include 13 | 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | 20 | namespace Theron 21 | { 22 | 23 | 24 | Receiver::Receiver() : 25 | mStringPoolRef(), 26 | mEndPoint(0), 27 | mName(), 28 | mAddress(), 29 | mMessageHandlers(), 30 | mCondition(), 31 | mMessagesReceived(0) 32 | { 33 | Initialize(); 34 | } 35 | 36 | 37 | Receiver::Receiver(EndPoint &endPoint, const char *const name) : 38 | mStringPoolRef(), 39 | mEndPoint(&endPoint), 40 | mName(name), 41 | mAddress(), 42 | mMessageHandlers(), 43 | mCondition(), 44 | mMessagesReceived(0) 45 | { 46 | Initialize(); 47 | } 48 | 49 | 50 | Receiver::~Receiver() 51 | { 52 | Release(); 53 | } 54 | 55 | 56 | void Receiver::Initialize() 57 | { 58 | // Register this receiver, claiming a unique address for this receiver. 59 | const uint32_t receiverIndex(Detail::StaticDirectory::Register(this)); 60 | 61 | if (mName.IsNull()) 62 | { 63 | char rawName[16]; 64 | Detail::NameGenerator::Generate(rawName, receiverIndex); 65 | 66 | const char *endPointName(0); 67 | if (mEndPoint) 68 | { 69 | endPointName = mEndPoint->GetName(); 70 | } 71 | 72 | char scopedName[256]; 73 | Detail::NameGenerator::Combine( 74 | scopedName, 75 | 256, 76 | rawName, 77 | 0, 78 | endPointName); 79 | 80 | mName = Detail::String(scopedName); 81 | } 82 | 83 | // Receivers are identified as a receiver by a framework index of zero. 84 | // All frameworks have non-zero indices, so all actors have non-zero framework indices. 85 | const Detail::Index index(0, receiverIndex); 86 | mAddress = Address(mName, index); 87 | 88 | // Register the receiver at its claimed address. 89 | Detail::Entry &entry(Detail::StaticDirectory::GetEntry(mAddress.AsInteger())); 90 | 91 | entry.Lock(); 92 | entry.SetEntity(this); 93 | entry.Unlock(); 94 | 95 | if (mEndPoint) 96 | { 97 | // Check that no mailbox with this name already exists. 98 | Detail::Index dummy; 99 | if (mEndPoint->Lookup(mName, dummy)) 100 | { 101 | THERON_FAIL_MSG("Can't create two actors or receivers with the same name"); 102 | } 103 | 104 | // Register the receiver 'mailbox' with the endPoint so it can be found using its name. 105 | if (!mEndPoint->Register(mName, index)) 106 | { 107 | THERON_FAIL_MSG("Failed to register receiver with the network endpoint"); 108 | } 109 | } 110 | } 111 | 112 | 113 | void Receiver::Release() 114 | { 115 | const Address &address(GetAddress()); 116 | 117 | // Deregister the receiver 'mailbox' with the endPoint so it can't be found anymore. 118 | if (mEndPoint) 119 | { 120 | mEndPoint->Deregister(address.GetName()); 121 | } 122 | 123 | // Deregister the receiver, so that the worker threads will leave it alone. 124 | Detail::StaticDirectory::Deregister(address.AsInteger()); 125 | 126 | mCondition.GetMutex().Lock(); 127 | 128 | // Free all currently allocated handler objects. 129 | while (Detail::IReceiverHandler *const handler = mMessageHandlers.Front()) 130 | { 131 | mMessageHandlers.Remove(handler); 132 | AllocatorManager::GetCache()->Free(handler); 133 | } 134 | 135 | mCondition.GetMutex().Unlock(); 136 | } 137 | 138 | 139 | } // namespace Theron 140 | 141 | 142 | -------------------------------------------------------------------------------- /Theron/StringPool.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) by Ashton Mason. See LICENSE.txt for licensing information. 2 | 3 | 4 | #include 5 | #include 6 | 7 | #include 8 | #include 9 | 10 | 11 | #ifdef _MSC_VER 12 | #pragma warning(push) 13 | #pragma warning (disable:4996) // function or variable may be unsafe. 14 | #endif //_MSC_VER 15 | 16 | 17 | namespace Theron 18 | { 19 | namespace Detail 20 | { 21 | 22 | 23 | StringPool *StringPool::smInstance = 0; 24 | Mutex StringPool::smReferenceMutex; 25 | uint32_t StringPool::smReferenceCount = 0; 26 | 27 | 28 | void StringPool::Reference() 29 | { 30 | Lock lock(smReferenceMutex); 31 | 32 | // Create the singleton instance if this is the first reference. 33 | if (smReferenceCount++ == 0) 34 | { 35 | IAllocator *const allocator(AllocatorManager::GetCache()); 36 | void *const memory(allocator->AllocateAligned(sizeof(StringPool), THERON_CACHELINE_ALIGNMENT)); 37 | smInstance = new (memory) StringPool(); 38 | } 39 | } 40 | 41 | 42 | void StringPool::Dereference() 43 | { 44 | Lock lock(smReferenceMutex); 45 | 46 | // Destroy the singleton instance if this was the last reference. 47 | if (--smReferenceCount == 0) 48 | { 49 | IAllocator *const allocator(AllocatorManager::GetCache()); 50 | smInstance->~StringPool(); 51 | allocator->Free(smInstance, sizeof(StringPool)); 52 | } 53 | } 54 | 55 | 56 | StringPool::StringPool() 57 | { 58 | } 59 | 60 | 61 | StringPool::~StringPool() 62 | { 63 | } 64 | 65 | 66 | const char *StringPool::Lookup(const char *const str) 67 | { 68 | // Hash the string value to a bucket index. 69 | const uint32_t index(Hash(str)); 70 | THERON_ASSERT(index < BUCKET_COUNT); 71 | Bucket &bucket(mBuckets[index]); 72 | 73 | // Lock the mutex after computing the hash. 74 | Lock lock(mMutex); 75 | return bucket.Lookup(str); 76 | } 77 | 78 | 79 | } // namespace Detail 80 | } // namespace Theron 81 | 82 | 83 | #ifdef _MSC_VER 84 | #pragma warning(pop) 85 | #endif //_MSC_VER 86 | -------------------------------------------------------------------------------- /Theron/YieldPolicy.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) by Ashton Mason. See LICENSE.txt for licensing information. 2 | 3 | 4 | #include 5 | #include 6 | 7 | #include 8 | #include 9 | 10 | 11 | namespace Theron 12 | { 13 | namespace Detail 14 | { 15 | 16 | 17 | void YieldPolicy::Hybrid(const uint32_t counter) 18 | { 19 | if (counter < 10) 20 | { 21 | Utils::YieldToHyperthread(); 22 | } 23 | else if (counter < 20) 24 | { 25 | for (uint32_t i = 0; i < 50; ++i) 26 | { 27 | Utils::YieldToHyperthread(); 28 | } 29 | } 30 | else if (counter < 22) 31 | { 32 | Utils::YieldToLocalThread(); 33 | } 34 | else 35 | { 36 | Utils::YieldToAnyThread(); 37 | } 38 | } 39 | 40 | 41 | void YieldPolicy::Spin(const uint32_t counter) 42 | { 43 | // This 'busy-wait' implementation never yields or sleeps. 44 | // It does however pause to allow another thread running on the same hyperthreaded core to proceed. 45 | if (counter < 10) 46 | { 47 | Utils::YieldToHyperthread(); 48 | } 49 | else if (counter < 20) 50 | { 51 | for (uint32_t i = 0; i < 50; ++i) 52 | { 53 | Utils::YieldToHyperthread(); 54 | } 55 | } 56 | else if (counter < 30) 57 | { 58 | for (uint32_t i = 0; i < 100; ++i) 59 | { 60 | Utils::YieldToHyperthread(); 61 | } 62 | } 63 | else 64 | { 65 | for (uint32_t i = 0; i < 200; ++i) 66 | { 67 | Utils::YieldToHyperthread(); 68 | } 69 | } 70 | } 71 | 72 | 73 | } // namespace Detail 74 | } // namespace Theron 75 | 76 | 77 | -------------------------------------------------------------------------------- /Theron/mainpage.txt: -------------------------------------------------------------------------------- 1 | 2 | /** 3 | 4 | @mainpage API reference 5 | 6 |

7 | This is the API reference documentation for Theron. 8 | Click on the heading tabs above for details of classes, namespaces and files within the distribution. 9 |

10 | 11 |

12 |

18 |

19 | 20 |

21 | See the online documentation for the latest version of this API documentation, plus the following useful resources: 22 |

23 | 24 |

25 |

33 |

34 | 35 |

36 | If you have any questions, feedback or bug reports, please send them to me at 37 | ash@ashtonmason.net. 38 |

39 | 40 |

41 | Thanks
42 | Ashton Mason 43 |

44 | 45 | */ 46 | 47 | -------------------------------------------------------------------------------- /Tutorial/Alignment/Alignment.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) by Ashton Mason. See LICENSE.txt for licensing information. 2 | 3 | 4 | #include 5 | 6 | #include 7 | 8 | 9 | // We need to disable this irritating level-4 warning in Visual C++ builds. 10 | #ifdef _MSC_VER 11 | #pragma warning(disable:4324) 12 | #endif // _MSC_VER 13 | 14 | 15 | #define CACHE_ALIGNMENT 64 16 | 17 | 18 | // A message type that, for some reason, must always be allocated on a cache-line. 19 | struct THERON_PREALIGN(CACHE_ALIGNMENT) AlignedMessage 20 | { 21 | AlignedMessage(const int value) : mValue(value) { } 22 | int mValue; 23 | 24 | } THERON_POSTALIGN(CACHE_ALIGNMENT); 25 | 26 | 27 | // Notify Theron of the alignment requirements of the message type. 28 | THERON_ALIGN_MESSAGE(AlignedMessage, CACHE_ALIGNMENT); 29 | 30 | 31 | // A simple actor that prints out the memory addresses of messages it receives. 32 | // For the sake of the example we assume that the actor type also requires 33 | // cache-line alignment. The same pair of macro's can be used here too. 34 | class THERON_PREALIGN(CACHE_ALIGNMENT) AlignedActor : public Theron::Actor 35 | { 36 | public: 37 | 38 | inline AlignedActor(Theron::Framework &framework) : Theron::Actor(framework) 39 | { 40 | RegisterHandler(this, &AlignedActor::Handler); 41 | } 42 | 43 | private: 44 | 45 | inline void Handler(const AlignedMessage &message, const Theron::Address from) 46 | { 47 | // Print out the memory address of the message copy to check its alignment. 48 | printf("Received message aligned to %d bytes at address 0x%p\n", 49 | CACHE_ALIGNMENT, 50 | &message); 51 | 52 | if (!THERON_ALIGNED(&message, CACHE_ALIGNMENT)) 53 | { 54 | printf("ERROR: Received message isn't correctly aligned\n"); 55 | } 56 | 57 | Send(message, from); 58 | } 59 | 60 | } THERON_POSTALIGN(CACHE_ALIGNMENT); 61 | 62 | 63 | int main() 64 | { 65 | Theron::Framework framework; 66 | Theron::Receiver receiver; 67 | 68 | // Construct an instance of the aligned actor type on the stack. 69 | AlignedActor alignedActor(framework); 70 | 71 | // Print out its memory address to check that it's a multiple of 64 bytes as 72 | // required. This alignment of instances on the stack is performed by the compiler 73 | // and ensured by THERON_PREALIGN and THERON_POSTALIGN. 74 | printf("Constructed actor aligned to %d bytes at address 0x%p\n", 75 | CACHE_ALIGNMENT, 76 | &alignedActor); 77 | 78 | if (!THERON_ALIGNED(&alignedActor, CACHE_ALIGNMENT)) 79 | { 80 | printf("ERROR: Constructed actor isn't correctly aligned\n"); 81 | } 82 | 83 | // Construct an instance of the aligned message type on the stack. 84 | AlignedMessage alignedMessage(503); 85 | 86 | // Print out its memory address to check that it's a multiple of 64 bytes. 87 | printf("Constructed message aligned to %d bytes at address 0x%p\n", 88 | CACHE_ALIGNMENT, 89 | &alignedMessage); 90 | 91 | if (!THERON_ALIGNED(&alignedMessage, CACHE_ALIGNMENT)) 92 | { 93 | printf("ERROR: Constructed message isn't correctly aligned\n"); 94 | } 95 | 96 | // Send the aligned message to the address printer. The actor sees a different 97 | // copy of the message (because messages are copied when they are sent), yet 98 | // the copy should be correctly aligned as well. This second kind of alignment 99 | // is ensured by THERON_ALIGN_MESSAGE. Note however that it relies on the 100 | // allocator used by Theron supporting aligned allocation requests (and the 101 | // DefaultAllocator, used by default, does). 102 | if (!framework.Send( 103 | alignedMessage, 104 | receiver.GetAddress(), 105 | alignedActor.GetAddress())) 106 | { 107 | printf("ERROR: Failed to send message to address printer\n"); 108 | } 109 | 110 | // Wait for the reply to be sure the message was handled. 111 | receiver.Wait(); 112 | } 113 | 114 | -------------------------------------------------------------------------------- /Tutorial/Alignment/Alignment.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hpp;hxx;hm;inl;inc;xsd 11 | 12 | 13 | 14 | 15 | Source Files 16 | 17 | 18 | -------------------------------------------------------------------------------- /Tutorial/Client/Client.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) by Ashton Mason. See LICENSE.txt for licensing information. 2 | 3 | 4 | /* 5 | The Client and Server examples show how to perform distributed computing with Theron. 6 | */ 7 | 8 | #include "../Common/Utils.h" 9 | 10 | #include 11 | 12 | // NOTE: Must include xs.h before standard headers to avoid warnings in MS headers! 13 | #if THERON_XS 14 | #include 15 | #endif // THERON_XS 16 | 17 | #include 18 | #include 19 | #include 20 | 21 | #include 22 | 23 | 24 | #ifdef _MSC_VER 25 | #pragma warning(push) 26 | #pragma warning (disable:4996) // function or variable may be unsafe. 27 | #endif //_MSC_VER 28 | 29 | 30 | // Simple message type that can be copied with memcpy so safely sent over the network. 31 | struct TextMessage 32 | { 33 | explicit TextMessage(const char *const text) 34 | { 35 | mText[0] = '\0'; 36 | strcpy(mText, text); 37 | } 38 | 39 | char mText[256]; 40 | }; 41 | 42 | 43 | // In order to be sent over the network, message types must be registered. 44 | THERON_REGISTER_MESSAGE(TextMessage); 45 | 46 | 47 | int main(int argc, char *argv[]) 48 | { 49 | char buffer[256] = { '\0' }; 50 | 51 | if (argc < 3) 52 | { 53 | printf("Usage: Client \n"); 54 | printf("Use local IP address as client address, and IP address of remote host as server address.\n"); 55 | 56 | if (GetLocalIPAddress(buffer)) 57 | { 58 | printf("Local (client) IP address is %s.\n", buffer); 59 | } 60 | 61 | return 1; 62 | } 63 | 64 | printf("Connecting; start remote server.\n"); 65 | 66 | // Create a local endpoint. 67 | sprintf(buffer, "tcp://%s:5556", argv[1]); 68 | Theron::EndPoint endPoint("client", buffer); 69 | 70 | // Connect to the remote endpoint. 71 | sprintf(buffer, "tcp://%s:5555", argv[2]); 72 | if (!endPoint.Connect(buffer)) 73 | { 74 | printf("ERROR: Connection failed - check networking is enabled.\n"); 75 | return 1; 76 | } 77 | 78 | // The framework is tied to the endpoint. 79 | Theron::Framework framework(endPoint); 80 | 81 | // Send messages to the server in a loop until the user enters 'exit'. 82 | // Note that if the server hasn't started listening yet it may miss the first messages! 83 | printf("Enter lines of text (max 256 chars per line). Type 'exit' to end.\n"); 84 | 85 | while (strcmp(buffer, "exit") != 0) 86 | { 87 | // Send the text in a messages to the remote 'printer' actor using its unique name. 88 | scanf("%s", buffer); 89 | framework.Send( 90 | TextMessage(buffer), 91 | Theron::Address(), 92 | Theron::Address("printer")); 93 | } 94 | } 95 | 96 | 97 | #ifdef _MSC_VER 98 | #pragma warning(pop) 99 | #endif //_MSC_VER 100 | 101 | -------------------------------------------------------------------------------- /Tutorial/Client/Client.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hpp;hxx;hm;inl;inc;xsd 11 | 12 | 13 | 14 | 15 | Source Files 16 | 17 | 18 | 19 | 20 | Header Files 21 | 22 | 23 | -------------------------------------------------------------------------------- /Tutorial/Common/Utils.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) by Ashton Mason. See LICENSE.txt for licensing information. 2 | #ifndef COMMON_UTILS_H 3 | #define COMMON_UTILS_H 4 | 5 | 6 | #include 7 | 8 | // This file uses WinSock for local IP address discovery. 9 | #if THERON_XS && THERON_MSVC 10 | #include 11 | #endif 12 | 13 | #include 14 | 15 | 16 | #ifdef _MSC_VER 17 | #pragma warning(push) 18 | #pragma warning (disable:4996) // function or variable may be unsafe. 19 | #endif //_MSC_VER 20 | 21 | 22 | inline bool GetLocalIPAddress(char *const result) 23 | { 24 | if (result == 0) 25 | { 26 | return false; 27 | } 28 | 29 | // TODO: Currently only implemented in Visual Studio builds; 30 | // in theory it should be possible to support on other platforms too. 31 | #if THERON_XS && THERON_MSVC 32 | 33 | // From an article 'Socket Programming gethostbyname' by Guy Lecky-Thompson. 34 | // Initialize WinSock. 35 | WSADATA wsa_Data; 36 | if (WSAStartup(0x101, &wsa_Data) != 0) 37 | { 38 | return false; 39 | } 40 | 41 | // Get the local host name. 42 | char hostName[255]; 43 | if (gethostname(hostName, 255) != 0) 44 | { 45 | return false; 46 | } 47 | 48 | struct hostent *host_entry; 49 | host_entry = gethostbyname(hostName); 50 | 51 | char *localIP(0); 52 | localIP = inet_ntoa(*(struct in_addr *)*host_entry->h_addr_list); 53 | 54 | if (localIP == 0 || strlen(localIP) == 0) 55 | { 56 | return false; 57 | } 58 | 59 | result[0] = '\0'; 60 | strcpy(result, localIP); 61 | 62 | // Shut down WinSock. 63 | if (WSACleanup() == 0) 64 | { 65 | return true; 66 | } 67 | 68 | #endif 69 | 70 | return false; 71 | } 72 | 73 | 74 | #ifdef _MSC_VER 75 | #pragma warning(pop) 76 | #endif //_MSC_VER 77 | 78 | 79 | #endif // COMMON_UTILS_H 80 | -------------------------------------------------------------------------------- /Tutorial/CustomAllocators/CustomAllocators.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) by Ashton Mason. See LICENSE.txt for licensing information. 2 | 3 | 4 | #include 5 | #include 6 | 7 | #include 8 | 9 | #include 10 | 11 | 12 | #ifdef _MSC_VER 13 | #pragma warning(push) 14 | #pragma warning (disable:4324) // structure was padded due to __declspec(align()) 15 | #endif //_MSC_VER 16 | 17 | 18 | // A simple linear allocator implementing Theron::IAllocator. 19 | // It allocates from a memory buffer, never freeing, until it runs out. 20 | class LinearAllocator : public Theron::IAllocator 21 | { 22 | public: 23 | 24 | LinearAllocator(void *const buffer, const SizeType size) : 25 | mSpinLock(), 26 | mBuffer(static_cast(buffer)), 27 | mOffset(mBuffer), 28 | mEnd(mBuffer + size) 29 | { 30 | } 31 | 32 | virtual ~LinearAllocator() 33 | { 34 | } 35 | 36 | virtual void *Allocate(const SizeType size) 37 | { 38 | // Default 4-byte alignment. 39 | return AllocateAligned(size, 4); 40 | } 41 | 42 | virtual void *AllocateAligned(const SizeType size, const SizeType alignment) 43 | { 44 | unsigned char *allocation(0); 45 | 46 | mSpinLock.Lock(); 47 | 48 | allocation = mOffset; 49 | THERON_ALIGN(allocation, alignment); 50 | 51 | // Buffer used up yet? 52 | if (allocation + size <= mEnd) 53 | { 54 | mOffset = allocation + size; 55 | } 56 | else 57 | { 58 | allocation = 0; 59 | } 60 | 61 | mSpinLock.Unlock(); 62 | 63 | return static_cast(allocation); 64 | } 65 | 66 | virtual void Free(void *const /*memory*/) 67 | { 68 | } 69 | 70 | virtual void Free(void *const /*memory*/, const SizeType /*size*/) 71 | { 72 | } 73 | 74 | SizeType GetBytesAllocated() 75 | { 76 | return static_cast(mOffset - mBuffer); 77 | } 78 | 79 | private: 80 | 81 | LinearAllocator(const LinearAllocator &other); 82 | LinearAllocator &operator=(const LinearAllocator &other); 83 | 84 | Theron::Detail::SpinLock mSpinLock; // Used to ensure thread-safe access. 85 | unsigned char *mBuffer; // Base address of referenced memory buffer. 86 | unsigned char *mOffset; // Current place within referenced memory buffer. 87 | unsigned char *mEnd; // End of referenced memory buffer (exclusive). 88 | }; 89 | 90 | 91 | // A simple actor that sends back string messages it receives. 92 | class Replier : public Theron::Actor 93 | { 94 | public: 95 | 96 | Replier(Theron::Framework &framework) : Theron::Actor(framework) 97 | { 98 | RegisterHandler(this, &Replier::StringHandler); 99 | } 100 | 101 | private: 102 | 103 | void StringHandler(const std::string &message, const Theron::Address from) 104 | { 105 | Send(message, from); 106 | } 107 | }; 108 | 109 | 110 | int main() 111 | { 112 | // Construct a LinearAllocator around a memory buffer. 113 | // Note that the buffer needs to be quite big due to fixed memory overheads inside Theron. 114 | const unsigned int BUFFER_SIZE(1024 * 1024); 115 | unsigned char *const buffer = new unsigned char[BUFFER_SIZE]; 116 | LinearAllocator allocator(buffer, BUFFER_SIZE); 117 | 118 | // Set the custom allocator for use by Theron. 119 | // Note that can only be done once, at start of day. 120 | Theron::AllocatorManager::SetAllocator(&allocator); 121 | 122 | // Construct a framework and an actor, send the actor a message and wait for the reply. 123 | // We do this in a local scope to ensure that all Theron objects are destructed before 124 | // we delete the buffer! 125 | { 126 | Theron::Framework framework; 127 | Theron::Receiver receiver; 128 | Replier replier(framework); 129 | 130 | if (!framework.Send(std::string("base"), receiver.GetAddress(), replier.GetAddress())) 131 | { 132 | printf("ERROR: Failed to send message to replier\n"); 133 | } 134 | 135 | receiver.Wait(); 136 | } 137 | 138 | printf("Allocated %d bytes\n", static_cast(allocator.GetBytesAllocated())); 139 | 140 | delete [] buffer; 141 | } 142 | 143 | 144 | #ifdef _MSC_VER 145 | #pragma warning(pop) 146 | #endif //_MSC_VER 147 | 148 | -------------------------------------------------------------------------------- /Tutorial/CustomAllocators/CustomAllocators.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hpp;hxx;hm;inl;inc;xsd 11 | 12 | 13 | 14 | 15 | Source Files 16 | 17 | 18 | -------------------------------------------------------------------------------- /Tutorial/FileReader/FileReader.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hpp;hxx;hm;inl;inc;xsd 11 | 12 | 13 | 14 | 15 | Source Files 16 | 17 | 18 | -------------------------------------------------------------------------------- /Tutorial/HelloWorld/HelloWorld.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) by Ashton Mason. See LICENSE.txt for licensing information. 2 | 3 | 4 | #include 5 | #include 6 | 7 | #include 8 | 9 | 10 | // Actor type that prints strings. 11 | // Derives from Theron::Actor. 12 | class Printer : public Theron::Actor 13 | { 14 | public: 15 | 16 | // Constructor, passes the framework to the baseclass. 17 | Printer(Theron::Framework &framework) : Theron::Actor(framework) 18 | { 19 | // Register the message handler. 20 | RegisterHandler(this, &Printer::Print); 21 | } 22 | 23 | private: 24 | 25 | // Handler for messages of type std::string. 26 | void Print(const std::string &message, const Theron::Address from) 27 | { 28 | // Print the string. 29 | printf("%s\n", message.c_str()); 30 | 31 | // Send a dummy message back for synchronization. 32 | Send(0, from); 33 | } 34 | }; 35 | 36 | 37 | int main() 38 | { 39 | // Construct a framework and instantiate a Printer within it. 40 | Theron::Framework framework; 41 | Printer printer(framework); 42 | 43 | // Construct a receiver to receive the reply message. 44 | Theron::Receiver receiver; 45 | 46 | // Send a string message to the Printer. 47 | // We pass the address of the receiver as the 'from' address. 48 | if (!framework.Send( 49 | std::string("Hello world!"), 50 | receiver.GetAddress(), 51 | printer.GetAddress())) 52 | { 53 | printf("ERROR: Failed to send message\n"); 54 | } 55 | 56 | // Synchronize with the dummy message sent in reply to make sure we're done. 57 | receiver.Wait(); 58 | } 59 | 60 | -------------------------------------------------------------------------------- /Tutorial/HelloWorld/HelloWorld.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hpp;hxx;hm;inl;inc;xsd 11 | 12 | 13 | 14 | 15 | Source Files 16 | 17 | 18 | -------------------------------------------------------------------------------- /Tutorial/MessageRegistration/MessageRegistration.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) by Ashton Mason. See LICENSE.txt for licensing information. 2 | 3 | 4 | #include 5 | #include 6 | 7 | #include 8 | 9 | 10 | // Register our message types. Registering message types is an optional optimization. 11 | // It avoids a dependency on dynamic_cast, which relies on built-in C++ RTTI. 12 | THERON_REGISTER_MESSAGE(std::string); 13 | 14 | 15 | // A simple actor that sends back string messages it receives. 16 | class Replier : public Theron::Actor 17 | { 18 | public: 19 | 20 | inline Replier(Theron::Framework &framework) : Theron::Actor(framework) 21 | { 22 | RegisterHandler(this, &Replier::StringHandler); 23 | } 24 | 25 | private: 26 | 27 | inline void StringHandler(const std::string &message, const Theron::Address from) 28 | { 29 | printf("Received message '%s'\n", message.c_str()); 30 | Send(message, from); 31 | } 32 | }; 33 | 34 | 35 | int main() 36 | { 37 | Theron::Framework framework; 38 | Theron::Receiver receiver; 39 | Replier replier(framework); 40 | 41 | // Send the actor a message and wait for the reply, to check it's working. 42 | if (!framework.Send( 43 | std::string("Hello"), 44 | receiver.GetAddress(), 45 | replier.GetAddress())) 46 | { 47 | printf("ERROR: Failed to send message to replier\n"); 48 | } 49 | 50 | receiver.Wait(); 51 | } 52 | 53 | -------------------------------------------------------------------------------- /Tutorial/MessageRegistration/MessageRegistration.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hpp;hxx;hm;inl;inc;xsd 11 | 12 | 13 | 14 | 15 | Source Files 16 | 17 | 18 | -------------------------------------------------------------------------------- /Tutorial/Server/Server.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) by Ashton Mason. See LICENSE.txt for licensing information. 2 | 3 | 4 | /* 5 | The Client and Server examples show how to perform distributed computing with Theron. 6 | */ 7 | 8 | 9 | #include "../Common/Utils.h" 10 | 11 | #include 12 | 13 | // NOTE: Must include xs.h before standard headers to avoid warnings in MS headers! 14 | #if THERON_XS 15 | #include 16 | #endif // THERON_XS 17 | 18 | #include 19 | #include 20 | #include 21 | 22 | #include 23 | 24 | 25 | #ifdef _MSC_VER 26 | #pragma warning(push) 27 | #pragma warning (disable:4996) // function or variable may be unsafe. 28 | #endif //_MSC_VER 29 | 30 | 31 | // Simple message type that can be copied with memcpy so safely sent over the network. 32 | struct TextMessage 33 | { 34 | explicit TextMessage(const char *const text) 35 | { 36 | mText[0] = '\0'; 37 | strcpy(mText, text); 38 | } 39 | 40 | char mText[256]; 41 | }; 42 | 43 | 44 | // In order to be sent over the network, message types must be registered. 45 | THERON_REGISTER_MESSAGE(TextMessage); 46 | 47 | 48 | class Printer : public Theron::Actor 49 | { 50 | public: 51 | 52 | Printer(Theron::Framework &framework, const char *const name) : 53 | Theron::Actor(framework, name) 54 | { 55 | RegisterHandler(this, &Printer::Handler); 56 | } 57 | 58 | private: 59 | 60 | void Handler(const TextMessage &message, const Theron::Address /*from*/) 61 | { 62 | printf("%s\n", message.mText); 63 | if (strcmp(message.mText, "exit") == 0) 64 | { 65 | // Signal we're done. 66 | Send(0, Theron::Address("receiver")); 67 | } 68 | } 69 | }; 70 | 71 | 72 | int main(int argc, char *argv[]) 73 | { 74 | char buffer[256] = { '\0' }; 75 | 76 | if (argc < 3) 77 | { 78 | printf("Usage: Server \n"); 79 | printf("Use local IP address as server address, and IP address of remote host as client address.\n"); 80 | 81 | if (GetLocalIPAddress(buffer)) 82 | { 83 | printf("Local (server) IP address is %s.\n", buffer); 84 | } 85 | 86 | return 1; 87 | } 88 | 89 | printf("Connecting; start remote client.\n"); 90 | 91 | // Create a local endpoint. 92 | sprintf(buffer, "tcp://%s:5555", argv[1]); 93 | Theron::EndPoint endPoint("server", buffer); 94 | 95 | // Connect to the remote endpoint. 96 | sprintf(buffer, "tcp://%s:5556", argv[2]); 97 | if (!endPoint.Connect(buffer)) 98 | { 99 | printf("ERROR: Connection failed - check networking is enabled.\n"); 100 | return 1; 101 | } 102 | 103 | // The framework and receiver are tied to the endpoint. 104 | Theron::Receiver receiver(endPoint, "receiver"); 105 | Theron::Framework framework(endPoint); 106 | 107 | // The unique name of the actor allows the client to send it messages remotely. 108 | Printer printer(framework, "printer"); 109 | 110 | receiver.Wait(); 111 | } 112 | 113 | 114 | #ifdef _MSC_VER 115 | #pragma warning(pop) 116 | #endif //_MSC_VER 117 | 118 | -------------------------------------------------------------------------------- /Tutorial/Server/Server.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hpp;hxx;hm;inl;inc;xsd 11 | 12 | 13 | 14 | 15 | Source Files 16 | 17 | 18 | 19 | 20 | Header Files 21 | 22 | 23 | -------------------------------------------------------------------------------- /Tutorial/UnhandledMessages/UnhandledMessages.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) by Ashton Mason. See LICENSE.txt for licensing information. 2 | 3 | 4 | #include 5 | #include 6 | 7 | #include 8 | 9 | 10 | static void DumpMessage( 11 | const void *const data, 12 | const Theron::uint32_t size, 13 | const Theron::Address from) 14 | { 15 | printf("Unhandled %d byte message sent from address %d:\n", 16 | size, 17 | from.AsInteger()); 18 | 19 | // Dump the message as hex data. 20 | if (data) 21 | { 22 | const char *const format("[%d] 0x%08x\n"); 23 | 24 | const unsigned int *const begin(reinterpret_cast(data)); 25 | const unsigned int *const end(begin + size / sizeof(unsigned int)); 26 | 27 | for (const unsigned int *word(begin); word != end; ++word) 28 | { 29 | printf(format, static_cast(word - begin), *word); 30 | } 31 | } 32 | } 33 | 34 | 35 | // A simple actor that prints out strings it receives. 36 | class Printer : public Theron::Actor 37 | { 38 | public: 39 | 40 | Printer(Theron::Framework &framework) : Theron::Actor(framework) 41 | { 42 | // Register the handler for string messages. 43 | RegisterHandler(this, &Printer::Print); 44 | 45 | // Register the default handler for all other kinds of messages. 46 | // If we don't register our own default handler then the 'default' default 47 | // handler will be used, which asserts on receiving an unhandled message. 48 | SetDefaultHandler(this, &Printer::DefaultHandler); 49 | } 50 | 51 | private: 52 | 53 | void Print(const std::string &message, const Theron::Address from) 54 | { 55 | printf("%s\n", message.c_str()); 56 | 57 | // Send the message back for synchronization. 58 | Send(message, from); 59 | } 60 | 61 | // Default handler which handles messages of unrecognized types. 62 | // This is a 'blind' handler which takes the unhandled message as raw data. 63 | void DefaultHandler( 64 | const void *const data, 65 | const Theron::uint32_t size, 66 | const Theron::Address from) 67 | { 68 | DumpMessage(data, size, from); 69 | } 70 | }; 71 | 72 | 73 | // A handler object that reports any undelivered or unhandled messages. 74 | class FallbackHandler 75 | { 76 | public: 77 | 78 | // Fallback handler which handles any messages not handled by an actor. 79 | // This is a 'blind' handler which takes the unhandled message as raw data. 80 | void Handle( 81 | const void *const data, 82 | const Theron::uint32_t size, 83 | const Theron::Address from) 84 | { 85 | DumpMessage(data, size, from); 86 | } 87 | }; 88 | 89 | 90 | int main() 91 | { 92 | Theron::Receiver receiver; 93 | Theron::Address printerAddress; 94 | 95 | // Create a framework and register a fallback handler with it. 96 | Theron::Framework framework; 97 | FallbackHandler fallbackHandler; 98 | framework.SetFallbackHandler(&fallbackHandler, &FallbackHandler::Handle); 99 | 100 | { 101 | // Create a printer actor within a local scope and remember its address. 102 | Printer printer(framework); 103 | printerAddress = printer.GetAddress(); 104 | 105 | // Send the printer a message of a type which it doesn't handle. 106 | // This message reaches the printer but is handled by its default handler. 107 | framework.Send(103, receiver.GetAddress(), printerAddress); 108 | 109 | // Send the printer a string message to show that it actually works. 110 | framework.Send(std::string("hit"), receiver.GetAddress(), printerAddress); 111 | 112 | // Wait for the reply to the handled string message, for synchronization. 113 | receiver.Wait(); 114 | } 115 | 116 | // Send a string message to the printer's address, which is now stale. 117 | // This message never reaches an actor so is handled by the fallback handler. 118 | framework.Send(std::string("miss"), receiver.GetAddress(), printerAddress); 119 | } 120 | 121 | -------------------------------------------------------------------------------- /Tutorial/UnhandledMessages/UnhandledMessages.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hpp;hxx;hm;inl;inc;xsd 11 | 12 | 13 | 14 | 15 | Source Files 16 | 17 | 18 | --------------------------------------------------------------------------------