Integrate our kernel-level reference counting implementation.

This will serve as the basis for an async-safe shared_ptr/weak_ptr
reference counting implementation similar in design to the
C++11 APIs of the same name.

This code was previously written by myself for kernel-level use, and
the integration here is mostly unmodified from that code; the
implementation has not yet been attached to our async-safe allocator.

Issue: PLCR-570
This commit is contained in:
Landon Fuller 2015-07-06 16:07:51 -06:00
Родитель a14816189f
Коммит 5c9a53a2c8
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 28BBCFC35B80A3C4
13 изменённых файлов: 1677 добавлений и 1 удалений

Просмотреть файл

@ -235,6 +235,30 @@
0576DACA1B41EA12000BCA73 /* DynamicLoaderTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 0576DAC91B41EA12000BCA73 /* DynamicLoaderTests.mm */; };
0576DACB1B41EA12000BCA73 /* DynamicLoaderTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 0576DAC91B41EA12000BCA73 /* DynamicLoaderTests.mm */; };
0576DACC1B41EA12000BCA73 /* DynamicLoaderTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 0576DAC91B41EA12000BCA73 /* DynamicLoaderTests.mm */; };
0576DAD41B42F367000BCA73 /* Reference.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 0576DACE1B42F367000BCA73 /* Reference.hpp */; };
0576DAD51B42F367000BCA73 /* Reference.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 0576DACE1B42F367000BCA73 /* Reference.hpp */; };
0576DAD61B42F367000BCA73 /* Reference.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 0576DACE1B42F367000BCA73 /* Reference.hpp */; };
0576DAD71B42F367000BCA73 /* ReferenceType.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 0576DACF1B42F367000BCA73 /* ReferenceType.hpp */; };
0576DAD81B42F367000BCA73 /* ReferenceType.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 0576DACF1B42F367000BCA73 /* ReferenceType.hpp */; };
0576DAD91B42F367000BCA73 /* ReferenceType.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 0576DACF1B42F367000BCA73 /* ReferenceType.hpp */; };
0576DADA1B42F367000BCA73 /* ReferenceValue.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 0576DAD01B42F367000BCA73 /* ReferenceValue.hpp */; };
0576DADB1B42F367000BCA73 /* ReferenceValue.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 0576DAD01B42F367000BCA73 /* ReferenceValue.hpp */; };
0576DADC1B42F367000BCA73 /* ReferenceValue.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 0576DAD01B42F367000BCA73 /* ReferenceValue.hpp */; };
0576DADD1B42F367000BCA73 /* shared_ptr.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 0576DAD11B42F367000BCA73 /* shared_ptr.hpp */; };
0576DADE1B42F367000BCA73 /* shared_ptr.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 0576DAD11B42F367000BCA73 /* shared_ptr.hpp */; };
0576DADF1B42F367000BCA73 /* shared_ptr.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 0576DAD11B42F367000BCA73 /* shared_ptr.hpp */; };
0576DAE31B42F367000BCA73 /* weak_ptr.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 0576DAD31B42F367000BCA73 /* weak_ptr.hpp */; };
0576DAE41B42F367000BCA73 /* weak_ptr.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 0576DAD31B42F367000BCA73 /* weak_ptr.hpp */; };
0576DAE51B42F367000BCA73 /* weak_ptr.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 0576DAD31B42F367000BCA73 /* weak_ptr.hpp */; };
0576DAEA1B42F387000BCA73 /* ReferenceTypeTests.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0576DAE61B42F387000BCA73 /* ReferenceTypeTests.cpp */; };
0576DAEB1B42F387000BCA73 /* ReferenceTypeTests.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0576DAE61B42F387000BCA73 /* ReferenceTypeTests.cpp */; };
0576DAEC1B42F387000BCA73 /* ReferenceTypeTests.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0576DAE61B42F387000BCA73 /* ReferenceTypeTests.cpp */; };
0576DAED1B42F387000BCA73 /* shared_ptr_test.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0576DAE71B42F387000BCA73 /* shared_ptr_test.cpp */; };
0576DAEE1B42F387000BCA73 /* shared_ptr_test.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0576DAE71B42F387000BCA73 /* shared_ptr_test.cpp */; };
0576DAEF1B42F387000BCA73 /* shared_ptr_test.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0576DAE71B42F387000BCA73 /* shared_ptr_test.cpp */; };
0576DAF31B42F387000BCA73 /* weak_ptr_test.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0576DAE91B42F387000BCA73 /* weak_ptr_test.cpp */; };
0576DAF41B42F387000BCA73 /* weak_ptr_test.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0576DAE91B42F387000BCA73 /* weak_ptr_test.cpp */; };
0576DAF51B42F387000BCA73 /* weak_ptr_test.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0576DAE91B42F387000BCA73 /* weak_ptr_test.cpp */; };
0576DAF81B430285000BCA73 /* PLCrashAsyncDynamicLoader.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0576DAF61B430285000BCA73 /* PLCrashAsyncDynamicLoader.cpp */; };
0576DAF91B430285000BCA73 /* PLCrashAsyncDynamicLoader.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0576DAF61B430285000BCA73 /* PLCrashAsyncDynamicLoader.cpp */; };
0576DAFA1B430285000BCA73 /* PLCrashAsyncDynamicLoader.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0576DAF61B430285000BCA73 /* PLCrashAsyncDynamicLoader.cpp */; };
@ -531,6 +555,8 @@
05D0AE2E1B45EE2000296632 /* XCTestRunner.mm in Sources */ = {isa = PBXBuildFile; fileRef = 05D0AE2D1B45EE0900296632 /* XCTestRunner.mm */; };
05D0AE2F1B45EE3000296632 /* XCTestRunner.mm in Sources */ = {isa = PBXBuildFile; fileRef = 05D0AE2D1B45EE0900296632 /* XCTestRunner.mm */; };
05D0AE301B45EE3C00296632 /* XCTestRunner.mm in Sources */ = {isa = PBXBuildFile; fileRef = 05D0AE2D1B45EE0900296632 /* XCTestRunner.mm */; };
05D0AE421B4B1EBF00296632 /* async_stl.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 05D0AE411B4B1EBF00296632 /* async_stl.hpp */; };
05D0AE431B4B1EBF00296632 /* async_stl.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 05D0AE411B4B1EBF00296632 /* async_stl.hpp */; };
05D8FE4C16ACAA6E000ED70C /* AsyncAllocator.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 05D8FE4B16ACAA6E000ED70C /* AsyncAllocator.cpp */; };
05D8FE4D16ACAA6E000ED70C /* AsyncAllocator.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 05D8FE4B16ACAA6E000ED70C /* AsyncAllocator.cpp */; };
05D8FE4E16ACAA6E000ED70C /* AsyncAllocator.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 05D8FE4B16ACAA6E000ED70C /* AsyncAllocator.cpp */; };
@ -1245,6 +1271,14 @@
0576DABC1B41E227000BCA73 /* DynamicLoader.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DynamicLoader.cpp; sourceTree = "<group>"; };
0576DABD1B41E227000BCA73 /* DynamicLoader.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = DynamicLoader.hpp; sourceTree = "<group>"; };
0576DAC91B41EA12000BCA73 /* DynamicLoaderTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = DynamicLoaderTests.mm; sourceTree = "<group>"; };
0576DACE1B42F367000BCA73 /* Reference.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = Reference.hpp; sourceTree = "<group>"; };
0576DACF1B42F367000BCA73 /* ReferenceType.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = ReferenceType.hpp; sourceTree = "<group>"; };
0576DAD01B42F367000BCA73 /* ReferenceValue.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = ReferenceValue.hpp; sourceTree = "<group>"; };
0576DAD11B42F367000BCA73 /* shared_ptr.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = shared_ptr.hpp; sourceTree = "<group>"; };
0576DAD31B42F367000BCA73 /* weak_ptr.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = weak_ptr.hpp; sourceTree = "<group>"; };
0576DAE61B42F387000BCA73 /* ReferenceTypeTests.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ReferenceTypeTests.cpp; sourceTree = "<group>"; };
0576DAE71B42F387000BCA73 /* shared_ptr_test.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = shared_ptr_test.cpp; sourceTree = "<group>"; };
0576DAE91B42F387000BCA73 /* weak_ptr_test.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = weak_ptr_test.cpp; sourceTree = "<group>"; };
0576DAF61B430285000BCA73 /* PLCrashAsyncDynamicLoader.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PLCrashAsyncDynamicLoader.cpp; sourceTree = "<group>"; };
0576DAF71B430285000BCA73 /* PLCrashAsyncDynamicLoader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PLCrashAsyncDynamicLoader.h; sourceTree = "<group>"; };
0576DB031B432CC2000BCA73 /* PLCrashDLCompat.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PLCrashDLCompat.cpp; sourceTree = "<group>"; };
@ -1339,6 +1373,8 @@
05D0AE2B1B45EE0900296632 /* LICENSE_1_0.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = LICENSE_1_0.txt; sourceTree = "<group>"; };
05D0AE2C1B45EE0900296632 /* README.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = README.txt; sourceTree = "<group>"; };
05D0AE2D1B45EE0900296632 /* XCTestRunner.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = XCTestRunner.mm; sourceTree = "<group>"; };
05D0AE411B4B1EBF00296632 /* async_stl.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = async_stl.hpp; sourceTree = "<group>"; };
05D0AE471B4B2F6E00296632 /* PLCrashCatchTest.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = PLCrashCatchTest.hpp; path = "Other Sources/PLCrashCatchTest.hpp"; sourceTree = SOURCE_ROOT; };
05D8FE4B16ACAA6E000ED70C /* AsyncAllocator.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = AsyncAllocator.cpp; sourceTree = "<group>"; };
05D8FE5316ACAA81000ED70C /* AsyncAllocator.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = AsyncAllocator.hpp; sourceTree = "<group>"; };
05D8FE5716ACC8CD000ED70C /* AsyncAllocatorTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = AsyncAllocatorTests.mm; sourceTree = "<group>"; };
@ -1634,6 +1670,7 @@
0576DB101B4333D0000BCA73 /* PLCrashDLCompatTests.m */,
05659DF7174D2E1200D2EE21 /* PLCrashTestCase.h */,
05659DF8174D2E1200D2EE21 /* PLCrashTestCase.m */,
05D0AE471B4B2F6E00296632 /* PLCrashCatchTest.hpp */,
);
name = "Unit Testing";
sourceTree = "<group>";
@ -1673,6 +1710,21 @@
name = Locking;
sourceTree = "<group>";
};
0576DACD1B42F329000BCA73 /* Reference Counting */ = {
isa = PBXGroup;
children = (
0576DACE1B42F367000BCA73 /* Reference.hpp */,
0576DACF1B42F367000BCA73 /* ReferenceType.hpp */,
0576DAE61B42F387000BCA73 /* ReferenceTypeTests.cpp */,
0576DAD01B42F367000BCA73 /* ReferenceValue.hpp */,
0576DAD11B42F367000BCA73 /* shared_ptr.hpp */,
0576DAE71B42F387000BCA73 /* shared_ptr_test.cpp */,
0576DAD31B42F367000BCA73 /* weak_ptr.hpp */,
0576DAE91B42F387000BCA73 /* weak_ptr_test.cpp */,
);
name = "Reference Counting";
sourceTree = "<group>";
};
05920D1D177B9226001E8975 /* DWARF Unwind */ = {
isa = PBXGroup;
children = (
@ -1966,9 +2018,11 @@
0576DABD1B41E227000BCA73 /* DynamicLoader.hpp */,
0576DABC1B41E227000BCA73 /* DynamicLoader.cpp */,
0576DAC91B41EA12000BCA73 /* DynamicLoaderTests.mm */,
05D0AE3D1B4B16AA00296632 /* STL Compat */,
05A17DC316D7F7FB00888448 /* Thread State */,
0576DA741B3DC1CD000BCA73 /* Locking */,
05D8FE4916ACAA44000ED70C /* Allocator */,
0576DACD1B42F329000BCA73 /* Reference Counting */,
05A5E28517C0411F008A75E5 /* Linked List */,
05BB4CA0166D40B90075171B /* Memory Objects */,
05BB4C9F166D40AD0075171B /* Symbolication */,
@ -2007,6 +2061,14 @@
path = Catch;
sourceTree = "<group>";
};
05D0AE3D1B4B16AA00296632 /* STL Compat */ = {
isa = PBXGroup;
children = (
05D0AE411B4B1EBF00296632 /* async_stl.hpp */,
);
name = "STL Compat";
sourceTree = "<group>";
};
05D8FE4916ACAA44000ED70C /* Allocator */ = {
isa = PBXGroup;
children = (
@ -2294,6 +2356,7 @@
05EC51DD105316E900DB9D39 /* PLCrashLogWriterEncoding.h in Headers */,
05EC51DE105316E900DB9D39 /* PLCrashReport.h in Headers */,
05EC51E0105316E900DB9D39 /* PLCrashReportApplicationInfo.h in Headers */,
05D0AE431B4B1EBF00296632 /* async_stl.hpp in Headers */,
0573B4481681107F00395F2A /* PLCrashReportRegisterInfo.h in Headers */,
05EC51E2105316E900DB9D39 /* PLCrashReportBinaryImageInfo.h in Headers */,
0573B4491681108200395F2A /* PLCrashReportStackFrameInfo.h in Headers */,
@ -2330,10 +2393,12 @@
files = (
05CD318D0EE93A90000FDE88 /* CrashReporter.h in Headers */,
05CD339C0EE948EB000FDE88 /* PLCrashSignalHandler.h in Headers */,
0576DAD51B42F367000BCA73 /* Reference.hpp in Headers */,
059666E00EEDDFB8008A0601 /* PLCrashFrameWalker.h in Headers */,
059670270EEF6B1A008A0601 /* PLCrashLogWriter.h in Headers */,
05CD36D30EF25717000FDE88 /* PLCrashLogWriterEncoding.h in Headers */,
0576DAB71B41CCE0000BCA73 /* PLCrashAsyncAllocator.h in Headers */,
0576DAE41B42F367000BCA73 /* weak_ptr.hpp in Headers */,
05F411A80EF8DA31008050CF /* PLCrashReport.h in Headers */,
0576DA911B3DC81B000BCA73 /* AsyncPageAllocator.hpp in Headers */,
0576DB011B430285000BCA73 /* PLCrashAsyncDynamicLoader.h in Headers */,
@ -2342,6 +2407,7 @@
05F414860EF9BFAC008050CF /* PLCrashReportThreadInfo.h in Headers */,
05F415110EF9DD9B008050CF /* PLCrashReportBinaryImageInfo.h in Headers */,
05F415570EF9E078008050CF /* PLCrashReportExceptionInfo.h in Headers */,
0576DADB1B42F367000BCA73 /* ReferenceValue.hpp in Headers */,
05E734340EFAC46D005EDFB7 /* PLCrashAsyncSignalInfo.h in Headers */,
05E734F90EFAE59C005EDFB7 /* PLCrashReportSignalInfo.h in Headers */,
0576DA801B3DC210000BCA73 /* SpinLock.hpp in Headers */,
@ -2350,6 +2416,7 @@
054627B911D99D06007891C7 /* PLCrashReportFormatter.h in Headers */,
05BB83CF1364A77800D53B84 /* PLCrashReportProcessorInfo.h in Headers */,
05BB83F31364AD3E00D53B84 /* PLCrashReportMachineInfo.h in Headers */,
0576DAD81B42F367000BCA73 /* ReferenceType.hpp in Headers */,
05BB84881364EDF200D53B84 /* PLCrashSysctl.h in Headers */,
05EB2B1115B6FDA80066EB4D /* PLCrashReporterNSError.h in Headers */,
05D9E5471676598200B39833 /* PLCrashReportStackFrameInfo.h in Headers */,
@ -2373,6 +2440,7 @@
05BEC41917BAF92A0082CBFB /* PLCrashMachExceptionPortSet.h in Headers */,
05BEC43817BF1CB10082CBFB /* PLCrashReporterConfig.h in Headers */,
05A5E29117C04188008A75E5 /* PLCrashAsyncLinkedList.hpp in Headers */,
0576DADE1B42F367000BCA73 /* shared_ptr.hpp in Headers */,
05B929EA17C9336600B051E3 /* PLCrashUncaughtExceptionHandler.h in Headers */,
0513E23617D15ED400727919 /* PLCrashReportMachExceptionInfo.h in Headers */,
);
@ -2384,10 +2452,12 @@
files = (
05CD318F0EE93A90000FDE88 /* CrashReporter.h in Headers */,
05CD339E0EE948EB000FDE88 /* PLCrashSignalHandler.h in Headers */,
0576DAD61B42F367000BCA73 /* Reference.hpp in Headers */,
059666DE0EEDDFB8008A0601 /* PLCrashFrameWalker.h in Headers */,
0596702B0EEF6B1A008A0601 /* PLCrashLogWriter.h in Headers */,
05CD36D10EF25717000FDE88 /* PLCrashLogWriterEncoding.h in Headers */,
0576DAB81B41CCE0000BCA73 /* PLCrashAsyncAllocator.h in Headers */,
0576DAE51B42F367000BCA73 /* weak_ptr.hpp in Headers */,
05F411A60EF8DA31008050CF /* PLCrashReport.h in Headers */,
0576DA921B3DC81B000BCA73 /* AsyncPageAllocator.hpp in Headers */,
0576DB021B430285000BCA73 /* PLCrashAsyncDynamicLoader.h in Headers */,
@ -2396,6 +2466,7 @@
05F414820EF9BFAC008050CF /* PLCrashReportThreadInfo.h in Headers */,
05F4150D0EF9DD9B008050CF /* PLCrashReportBinaryImageInfo.h in Headers */,
05F415530EF9E078008050CF /* PLCrashReportExceptionInfo.h in Headers */,
0576DADC1B42F367000BCA73 /* ReferenceValue.hpp in Headers */,
05E734320EFAC46D005EDFB7 /* PLCrashAsyncSignalInfo.h in Headers */,
05E734F70EFAE59C005EDFB7 /* PLCrashReportSignalInfo.h in Headers */,
0576DA811B3DC210000BCA73 /* SpinLock.hpp in Headers */,
@ -2404,6 +2475,7 @@
054627BB11D99D06007891C7 /* PLCrashReportFormatter.h in Headers */,
05BB83CD1364A77800D53B84 /* PLCrashReportProcessorInfo.h in Headers */,
05BB83F51364AD3E00D53B84 /* PLCrashReportMachineInfo.h in Headers */,
0576DAD91B42F367000BCA73 /* ReferenceType.hpp in Headers */,
05BB848A1364EDF200D53B84 /* PLCrashSysctl.h in Headers */,
05EB2B1215B6FDA80066EB4D /* PLCrashReporterNSError.h in Headers */,
05D9E5481676598200B39833 /* PLCrashReportStackFrameInfo.h in Headers */,
@ -2427,6 +2499,7 @@
05BEC41A17BAF92A0082CBFB /* PLCrashMachExceptionPortSet.h in Headers */,
05BEC43917BF1CB10082CBFB /* PLCrashReporterConfig.h in Headers */,
05A5E29217C04188008A75E5 /* PLCrashAsyncLinkedList.hpp in Headers */,
0576DADF1B42F367000BCA73 /* shared_ptr.hpp in Headers */,
05B929EB17C9336600B051E3 /* PLCrashUncaughtExceptionHandler.h in Headers */,
0513E23717D15ED400727919 /* PLCrashReportMachExceptionInfo.h in Headers */,
);
@ -2504,7 +2577,9 @@
2D0E10461141F7DC00CE1BD6 /* PLCrashReportProcessInfo.h in Headers */,
054627AF11D998BB007891C7 /* PLCrashReportTextFormatter.h in Headers */,
0576DB001B430285000BCA73 /* PLCrashAsyncDynamicLoader.h in Headers */,
0576DAD71B42F367000BCA73 /* ReferenceType.hpp in Headers */,
054627BC11D99D06007891C7 /* PLCrashReportFormatter.h in Headers */,
0576DAE31B42F367000BCA73 /* weak_ptr.hpp in Headers */,
05BB83D11364A77800D53B84 /* PLCrashReportProcessorInfo.h in Headers */,
05BB83F11364AD3E00D53B84 /* PLCrashReportMachineInfo.h in Headers */,
05BB84861364EDF200D53B84 /* PLCrashSysctl.h in Headers */,
@ -2513,13 +2588,16 @@
0573B42D1681098E00395F2A /* PLCrashMachExceptionServer.h in Headers */,
05D8FE5416ACAA81000ED70C /* AsyncAllocator.hpp in Headers */,
FCE45A25B973D69EE5DDE269 /* PLCrashFrameStackUnwind.h in Headers */,
0576DADD1B42F367000BCA73 /* shared_ptr.hpp in Headers */,
05A17DCE16D7F82700888448 /* PLCrashAsyncThread.h in Headers */,
05A17DEC16DBCDBF00888448 /* PLCrashAsyncThread_x86.h in Headers */,
0576DAD41B42F367000BCA73 /* Reference.hpp in Headers */,
05A17DEE16DBCDBF00888448 /* PLCrashAsyncThread_arm.h in Headers */,
05F3CD6516DD6A58007911FB /* PLCrashFrameCompactUnwind.h in Headers */,
05F3CD7516DFC744007911FB /* PLCrashAsyncCompactUnwindEncoding.h in Headers */,
05659DEB17455DD400D2EE21 /* PLCrashAsyncDwarfEncoding.hpp in Headers */,
05E7485A1760D62A009B8745 /* PLCrashAsyncDwarfFDE.hpp in Headers */,
05D0AE421B4B1EBF00296632 /* async_stl.hpp in Headers */,
05E7486F1760D8AE009B8745 /* PLCrashAsyncDwarfCIE.hpp in Headers */,
05E7488B176135CF009B8745 /* PLCrashAsyncDwarfExpression.hpp in Headers */,
05E748AF17616D30009B8745 /* dwarf_stack.hpp in Headers */,
@ -2533,6 +2611,7 @@
05BEC41817BAF92A0082CBFB /* PLCrashMachExceptionPortSet.h in Headers */,
05BEC42E17BD4F400082CBFB /* PLCrashAsyncMachExceptionInfo.h in Headers */,
05A5E29017C04188008A75E5 /* PLCrashAsyncLinkedList.hpp in Headers */,
0576DADA1B42F367000BCA73 /* ReferenceValue.hpp in Headers */,
05B929E917C9336600B051E3 /* PLCrashUncaughtExceptionHandler.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
@ -3151,6 +3230,7 @@
0596702E0EEF6B51008A0601 /* PLCrashLogWriterTests.m in Sources */,
059674880EF0BB4A008A0601 /* PLCrashLogWriter.m in Sources */,
05EB2B0315B45DD00066EB4D /* PLCrashAsyncThread_current.S in Sources */,
0576DAED1B42F387000BCA73 /* shared_ptr_test.cpp in Sources */,
05EB2B0C15B4988E0066EB4D /* PLCrashAsyncThread_current.c in Sources */,
0596748E0EF0BB63008A0601 /* PLCrashFrameWalker.c in Sources */,
059674790EF0BA07008A0601 /* crash_report.proto in Sources */,
@ -3209,6 +3289,7 @@
05E7486B1760D891009B8745 /* PLCrashAsyncDwarfCIE.cpp in Sources */,
05E748721760DBBE009B8745 /* PLCrashAsyncDwarfCIETests.mm in Sources */,
05E748761760DBD0009B8745 /* PLCrashAsyncDwarfFDETests.mm in Sources */,
0576DAF31B42F387000BCA73 /* weak_ptr_test.cpp in Sources */,
05E7487F176118C2009B8745 /* PLCrashAsyncDwarfCFAStateEvaluation.cpp in Sources */,
05E74886176118F9009B8745 /* PLCrashAsyncDwarfCFAStateEvaluationTests.mm in Sources */,
05E74891176135CF009B8745 /* PLCrashAsyncDwarfExpression.cpp in Sources */,
@ -3235,6 +3316,7 @@
05507A531784DEE4009D5168 /* unwind_test_x86_frame.S in Sources */,
05C5880E1788CAA400BA118D /* unwind_test_x86_frameless.S in Sources */,
05C588121788F36800BA118D /* unwind_test_x86_frameless_big.S in Sources */,
0576DAEA1B42F387000BCA73 /* ReferenceTypeTests.cpp in Sources */,
05C588161788F3E700BA118D /* unwind_test_x86_unusual.S in Sources */,
05C5881A1788F48500BA118D /* unwind_test_x86_disable_compact_frame.S in Sources */,
05920D36178B310A001E8975 /* unwind_test_arm.S in Sources */,
@ -3287,6 +3369,7 @@
C2198DDE1640188C006EB46A /* PLCrashAsyncObjCSection.mm in Sources */,
C2198DE516402B8A006EB46A /* PLCrashAsyncObjCSectionTests.m in Sources */,
C260228B1642FCA6007FC29F /* PLCrashAsyncSymbolication.c in Sources */,
0576DAEE1B42F387000BCA73 /* shared_ptr_test.cpp in Sources */,
C26022911642FE9B007FC29F /* PLCrashAsyncSymbolicationTests.m in Sources */,
C2198E0B16441CF5006EB46A /* PLCrashAsyncMachOString.c in Sources */,
C21688FA16445344000F90ED /* PLCrashAsyncMachOStringTests.m in Sources */,
@ -3305,6 +3388,7 @@
05F3CD6A16DD6A7A007911FB /* PLCrashFrameCompactUnwindTests.m in Sources */,
05F3CD7D16DFC744007911FB /* PLCrashAsyncCompactUnwindEncoding.c in Sources */,
05F3CD8216DFC78D007911FB /* PLCrashAsyncCompactUnwindEncodingTests.m in Sources */,
0576DAEB1B42F387000BCA73 /* ReferenceTypeTests.cpp in Sources */,
05659DF317456A4000D2EE21 /* PLCrashAsyncDwarfEncodingTests.mm in Sources */,
0576DB0A1B432CC2000BCA73 /* PLCrashDLCompat.cpp in Sources */,
05A17DCA16D7F81600888448 /* PLCrashAsyncThread.c in Sources */,
@ -3341,6 +3425,7 @@
05920D2F17848B85001E8975 /* unwind_test_x86_64_frameless.S in Sources */,
05920D331784C808001E8975 /* unwind_test_x86_64_frameless_big.S in Sources */,
0576DAC31B41E227000BCA73 /* DynamicLoader.cpp in Sources */,
0576DAF41B42F387000BCA73 /* weak_ptr_test.cpp in Sources */,
0576DAA51B3E0856000BCA73 /* AsyncAllocatable.cpp in Sources */,
05507A501784DA8A009D5168 /* unwind_test_x86_64_unusual.S in Sources */,
05507A541784DEE4009D5168 /* unwind_test_x86_frame.S in Sources */,
@ -3375,6 +3460,7 @@
059670300EEF6B51008A0601 /* PLCrashLogWriterTests.m in Sources */,
059674970EF0BBB4008A0601 /* PLCrashLogWriter.m in Sources */,
05EB2B0515B45DE00066EB4D /* PLCrashAsyncThread_current.S in Sources */,
0576DAEF1B42F387000BCA73 /* shared_ptr_test.cpp in Sources */,
05EB2B0A15B498880066EB4D /* PLCrashAsyncThread_current.c in Sources */,
059674980EF0BBB4008A0601 /* PLCrashFrameWalker.c in Sources */,
0596749B0EF0BBB4008A0601 /* crash_report.proto in Sources */,
@ -3433,6 +3519,7 @@
05E74858175E5370009B8745 /* PLCrashAsyncDwarfPrimitivesTests.mm in Sources */,
05E748651760D64D009B8745 /* PLCrashAsyncDwarfFDE.cpp in Sources */,
05E7486D1760D891009B8745 /* PLCrashAsyncDwarfCIE.cpp in Sources */,
0576DAF51B42F387000BCA73 /* weak_ptr_test.cpp in Sources */,
05E748741760DBBE009B8745 /* PLCrashAsyncDwarfCIETests.mm in Sources */,
05E748781760DBD0009B8745 /* PLCrashAsyncDwarfFDETests.mm in Sources */,
05E74881176118C2009B8745 /* PLCrashAsyncDwarfCFAStateEvaluation.cpp in Sources */,
@ -3459,6 +3546,7 @@
05507A511784DA8A009D5168 /* unwind_test_x86_64_unusual.S in Sources */,
05507A551784DEE4009D5168 /* unwind_test_x86_frame.S in Sources */,
05C588101788CAA400BA118D /* unwind_test_x86_frameless.S in Sources */,
0576DAEC1B42F387000BCA73 /* ReferenceTypeTests.cpp in Sources */,
05C588141788F36800BA118D /* unwind_test_x86_frameless_big.S in Sources */,
05C588181788F3E700BA118D /* unwind_test_x86_unusual.S in Sources */,
05C5881C1788F48500BA118D /* unwind_test_x86_disable_compact_frame.S in Sources */,

2
Dependencies/Catch/README.txt поставляемый
Просмотреть файл

@ -15,3 +15,5 @@ XCTestRunner.mm
MIT License
The test runner code is only used by the PLCrashReporter unit tests; it is not incorporated into the
PLCrashReporter library.
Modifications:
- Replaced direct inclusion of "catch.hpp" with our own "PLCrashCatchTest.hpp" shim.

2
Dependencies/Catch/XCTestRunner.mm поставляемый
Просмотреть файл

@ -26,7 +26,7 @@
*/
#define CATCH_CONFIG_RUNNER
#include "catch.hpp"
#include "PLCrashCatchTest.hpp"
#include <XCTest/XCTest.h>
#include <inttypes.h>

Просмотреть файл

@ -0,0 +1,49 @@
/*
* Copyright (c) 2015 Plausible Labs Cooperative, Inc.
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use,
* copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef PLCRASH_CATCH_TEST_HPP
#define PLCRASH_CATCH_TEST_HPP
#include "async_stl.hpp"
/*
* Provide a C++11-compatible nullptr_t for use in Catch; this is necessary to avoid overload ambiguity
* in catch caused by our own usage of atl::nullptr_t.
*
* If we adopt a minimum requirement of a C++11-capable STL (which will require that we drop
* support for Mac OS X 10.6), this should be removed.
*/
#define CATCH_CONFIG_CPP11_NULLPTR
namespace std {
inline namespace _async_compat {
typedef plcrash::async::atl::nullptr_t nullptr_t;
}
}
#include "catch.hpp"
#endif /* PLCRASH_CATCH_TEST_HPP */

241
Source/Reference.hpp Normal file
Просмотреть файл

@ -0,0 +1,241 @@
/*
* Copyright (c) 2014 - 2015 Plausible Labs Cooperative, Inc.
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use,
* copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef PLCRASH_ASYNC_REFERENCE_H
#define PLCRASH_ASYNC_REFERENCE_H
#include "PLCrashMacros.h"
#include "ReferenceValue.hpp"
#include "ReferenceType.hpp"
/**
* @internal
* @ingroup plcrash_async
*
* @{
*/
PLCR_CPP_BEGIN_ASYNC_NS
namespace refcount {
/**
* @internal
*
* Manages access to (and reference counting of) of a backing ReferenceValue instance.
*
* This class serves as a shared implementation used by both shared_ptr and weak_ptr.
*
* @tparam T The referenced object type.
* @tparam ReferenceValue The referenced object container.
* @tparam ReferenceType The reference type implementation (strong, weak, etc).
*
* @par Thread Safety
*
* Reference counting is fully thread-safe, and multiple Reference instances may reference the same object. A single
* Reference instance, however, must not be concurrently mutated -- or accessed during mutation -- without
* external synchronization.
*/
template <typename T, class ReferencedValue, class ReferenceType> class Reference {
public:
/**
* Construct a new Reference, optionally incrementing the reference count of @a value.
*
* @param value The value for the newly constructed reference, or NULL.
* @param acquireRefererence If true, the reference count of a (non-NULL) @a value will be incremented.
*/
Reference(ReferencedValue *value, bool acquireReference) : _v(nullptr) {
put(value, acquireReference);
}
/**
* Construct an empty reference.
*/
constexpr Reference() noexcept : _v(nullptr) { }
/**
* Deallocate this reference and decrement the managed object's reference count. If the reference count is zero,
* the referenced object is destroyed.
*/
~Reference() {
release();
}
/** Returns a pointer to the managed object. */
inline T* get (void) const {
if (_v == nullptr) {
return nullptr;
} else {
return _v->get();
}
}
/** Release ownership of the managed object, if any. Upon return, the reference will be empty. */
inline void clear () {
release();
}
/**
* Return the current retain count for the managed object, or 0 if there is no managed object. The retain count should
* be equivalent to the number of shared_ptr instances managing the current object.
*
* Note that the reference count is unreliable, and should not be used.
*/
size_t referenceCount (void) const {
if (this->_v == NULL) {
return 0;
} else {
return _v->refs;
}
}
/**
* Move constructor; the move destination adopts ownership of the value referenced by @a ref.
*
* @param ref The shared pointer to be moved.
*/
Reference(Reference &&ref) noexcept : Reference(ref.sharedValue(), false) {
/* Now that we've moved ownership, forcibly discard the previous owner's reference. */
ref.abandon();
}
/**
* Move assignment operator; the move destination adopts ownership of the value referenced by @a ref.
*
* @param ref The shared pointer to be moved.
*/
Reference & operator= (Reference &&ref) noexcept {
/* Assume ownership of the shared value */
put(ref.sharedValue(), false);
/* Forcibly discard the previous owner's reference. */
ref.abandon();
return *this;
}
/**
* Copy constructor; the copy destination retains an additional reference to the value referenced by @a ref.
*
* @param ref The shared pointer to be copied.
*/
Reference(const Reference &ref) noexcept : Reference(ref.sharedValue(), true) { }
/**
* Copy assignment operator; the copy destination retains an additional reference to the value referenced by @a ref.
*
* @param ref The shared pointer to be copied.
*/
Reference &operator= (const Reference &ref) noexcept {
/* Claim a reference */
put(ref.sharedValue(), true);
return *this;
}
/**
* Return a borrowed reference to the underlying referenced value.
*/
ReferencedValue *sharedValue (void) const noexcept {
return _v;
}
/**
* Return true if this object holds a reference to an empty (null) pointer.
*/
bool isEmpty (void) const {
if (_v == nullptr) {
return true;
} else {
return false;
}
}
/**
* Set the internal reference counted value to @a target, releasing the current value, if any.
*
* @param newValue The value to be stored, or nullptr.
* @param acquireReference If true, and @a target is not nullptr, the reference count of @a target will be
* incremented. If false, a reference must have already been acquired (eg, by initializing `newValue` with a
* reference count of 1).
*/
void put (ReferencedValue *newValue, bool acquireReference) {
/* Already referencing this value? */
if (_v == newValue)
return;
/* Drop our existing shared value (if any). */
release();
/* Save the new value and, if requested and non-NULL, increment its reference count */
_v = newValue;
if (acquireReference && _v != nullptr) {
retain();
}
}
private:
/**
* Release our reference to the shared value.
*/
void release (void) noexcept {
if (_v != nullptr) {
_refType.release(_v);
_v = nullptr;
}
}
/**
* Retain a reference to the shared value.
*/
void retain (void) noexcept {
if (_v != nullptr) {
_refType.retain(_v);
}
}
/**
* Abandon the internal reference counted value; this is primarily used when implementing ownership move behavior,
* as the move target will assume ownership of our current reference.
*/
inline void abandon (void) {
_v = nullptr;
}
/** The reference counted value. */
ReferencedValue *_v;
/** The reference type */
ReferenceType _refType;
};
} /* namespace refcount */
PLCR_CPP_END_ASYNC_NS
/**
* @}
*/
#endif /* PLCRASH_ASYNC_REFERENCE_H */

114
Source/ReferenceType.hpp Normal file
Просмотреть файл

@ -0,0 +1,114 @@
/*
* Copyright (c) 2014 Plausible Labs Cooperative, Inc.
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use,
* copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef PLCRASH_ASYNC_REFERENCE_TYPE_H
#define PLCRASH_ASYNC_REFERENCE_TYPE_H
#include "ReferenceValue.hpp"
#include "PLCrashMacros.h"
/**
* @internal
* @ingroup plcrash_async
*
* @{
*/
PLCR_CPP_BEGIN_ASYNC_NS
namespace refcount {
/**
* A weak reference type. Will adjust a ReferenceValue's weak reference count, and deallocate
* the ReferenceValue instance upon hitting a weak reference count of zero.
*
* @tparam The type of object managed by the target ReferenceValue.
*/
template <typename T, typename ReferencedValue> class WeakReferenceType {
public:
/**
* Atomically increment the internal reference count.
*/
inline void retain (ReferencedValue *sharedValue) noexcept {
__sync_fetch_and_add(&sharedValue->weakRefs, 1);
}
/**
* Atomically decrement the internal reference count.
*/
inline void release (ReferencedValue *sharedValue) noexcept {
/*
* Atomically decrement the weak reference. If this hits zero, then all strong and weak references
* are zero (an implicit weak reference is held by all strong references), and the sharedValue itself
* can be deallocated.
*/
if (__sync_fetch_and_sub(&sharedValue->weakRefs, 1) == 1) {
delete sharedValue;
}
}
};
/**
* A strong reference type. Will adjust a ReferenceValue's strong reference count, destroying the
* backing object when the strong reference count hits zero.
*
* @tparam The type of object managed by the target ReferenceValue.
*/
template <typename T, typename ReferencedValue> class StrongReferenceType {
public:
/** Atomically increment the internal reference count. */
inline void retain (ReferencedValue *sharedValue) noexcept {
__sync_fetch_and_add(&sharedValue->refs, 1);
}
/**
* Atomically decrement the internal reference count, deallocating this object if the
* reference count has hit zero.
*/
inline void release (ReferencedValue *sharedValue) noexcept {
/* If the strong reference count hits zero, the value itself can be deconstructed/deallocated, and our
* implicit weak reference may also be discarded. */
if (__sync_fetch_and_sub(&sharedValue->refs, 1) == 1) {
sharedValue->destroy();
/* Discard the implicit weak reference held by all strong references. If this is the last weak reference,
* this will deallocate the sharedValue itself. */
_weak.release(sharedValue);
}
}
private:
/** Weak reference handler */
WeakReferenceType<T, ReferencedValue> _weak;
};
} /* namespace refcount */
PLCR_CPP_END_ASYNC_NS
/**
* @}
*/
#endif /* PLCRASH_ASYNC_REFERENCE_TYPE_H */

Просмотреть файл

@ -0,0 +1,172 @@
/*
* Copyright (c) 2014 - 2015 Plausible Labs Cooperative, Inc.
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use,
* copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
#include "PLCrashCatchTest.hpp"
#include "ReferenceValue.hpp"
#include "ReferenceType.hpp"
using namespace plcrash::async;
using namespace plcrash::async::refcount;
PLCR_CPP_BEGIN_ASYNC_NS
/** A test value class that increments and decrements a counter on construction and destruction, respectively */
class RefTestTarget {
public:
/* Increment _destCount on construction */
RefTestTarget (ssize_t *destCount) : _destCount(destCount) { *_destCount = *_destCount + 1; }
/* Copy and move constructors that delegate to our standard _destCount-modifying constructor */
RefTestTarget (RefTestTarget &other) : RefTestTarget(other._destCount) { }
RefTestTarget (RefTestTarget &&other) : RefTestTarget(other._destCount) { }
/* Decrement _destCount on destruction */
~RefTestTarget () { *_destCount = *_destCount - 1; }
private:
ssize_t *_destCount;
};
TEST_CASE("StrongReferenceType") {
/** The reference type under test */
StrongReferenceType<RefTestTarget, InlineReferencedValue<RefTestTarget>> refType;
ssize_t count = 0;
/* Allocate a test value we'll use with the reftype */
auto value = new InlineReferencedValue<RefTestTarget>(&count);
REQUIRE(value->refs == (size_t)1);
REQUIRE(value->weakRefs == (size_t)1);
REQUIRE(count == 1);
WHEN("Retaining") {
THEN("The strong reference count should be incremented") {
refType.retain(value);
REQUIRE(value->refs == (size_t)2);
REQUIRE(value->weakRefs == (size_t)1);
refType.release(value);
}
}
WHEN("Releasing") {
THEN("The strong reference count should be decremented") {
refType.retain(value);
REQUIRE(value->refs == (size_t)2);
REQUIRE(value->weakRefs == (size_t)1);
refType.release(value);
REQUIRE(value->refs == (size_t)1);
REQUIRE(value->weakRefs == (size_t)1);
}
THEN("The underlying object should be deconstructed when the strong reference count hits 0") {
REQUIRE(count == 1);
refType.release(value);
REQUIRE(count == 0);
/* Mark our value as already deallocated, avoiding a double-free below */
value = nullptr;
}
}
/* Clean up our allocated test value, if not already done in a test. This should result in a balanced
* construction/destruction count. */
if (value != nullptr) {
REQUIRE(value->refs == (size_t)1);
refType.release(value);
}
REQUIRE(count == 0);
}
TEST_CASE("WeakReferenceType") {
/** The reference type under test */
WeakReferenceType<RefTestTarget, InlineReferencedValue<RefTestTarget>> refType;
/** A strong reference type that we'll use to test weak/strong interaction */
StrongReferenceType<RefTestTarget, InlineReferencedValue<RefTestTarget>> strongRefType;
ssize_t count = 0;
/* Allocate a test value we'll use with the reftype */
auto value = new InlineReferencedValue<RefTestTarget>(&count);
REQUIRE(value->refs == (size_t)1);
REQUIRE(value->weakRefs == (size_t)1);
REQUIRE(count == 1);
WHEN("Retaining") {
THEN("The weak reference count should be incremented") {
refType.retain(value);
REQUIRE(value->refs == (size_t)1);
REQUIRE(value->weakRefs == (size_t)2);
refType.release(value);
}
}
WHEN("Releasing") {
THEN("The weak reference count should be decremented") {
refType.retain(value);
REQUIRE(value->refs == (size_t)1);
REQUIRE(value->weakRefs == (size_t)2);
refType.release(value);
REQUIRE(value->refs == (size_t)1);
REQUIRE(value->weakRefs == (size_t)1);
}
THEN("With a weak reference held, the value reference should not be deallocated when the strong reference count hits 0") {
/* Create a new weak reference. */
refType.retain(value);
REQUIRE(value->weakRefs == (size_t)2);
/* Release the only strong reference. */
REQUIRE(count == 1);
strongRefType.release(value);
/* The underlying object should have had its destructor called. */
REQUIRE(count == 0);
/* But our value should still exist with a live weak reference count. */
REQUIRE(value->refs == (size_t)0);
REQUIRE(value->weakRefs == (size_t)1);
/* Drop our weak reference, triggering actual deallocation. */
refType.release(value);
/* Mark our value as already deallocated, avoiding a double-free below. */
value = nullptr;
}
}
/* Clean up our allocated test value, if not already done in a test. This should result in a balanced
* construction/destruction count. */
if (value != nullptr) {
REQUIRE(value->refs == (size_t)1);
REQUIRE(value->weakRefs == (size_t)1);
strongRefType.release(value);
}
REQUIRE(count == 0);
}
PLCR_CPP_END_ASYNC_NS

137
Source/ReferenceValue.hpp Normal file
Просмотреть файл

@ -0,0 +1,137 @@
/*
* Copyright (c) 2014 - 2015 Landon Fuller <landon@landonf.org>.
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use,
* copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
#include "PLCrashMacros.h"
#include "PLCrashAsync.h"
#include "async_stl.hpp"
#ifndef PLCRASH_ASYNC_REFERENCE_VALUE_H
#define PLCRASH_ASYNC_REFERENCE_VALUE_H
/**
* @internal
* @ingroup plcrash_async
*
* @{
*/
PLCR_CPP_BEGIN_ASYNC_NS
namespace refcount {
/**
* @internal
* An abstract reference counted value. The lifetime of this object -- and the destruction of its
* backing object of type `T` -- is entirely defined and managed by a corresponding ReferenceType instance.
*
* @tparam T The type held by this referenced value.
*/
template <typename T> class ReferenceValue {
public:
/**
* Construct an empty referenced value with a reference count of 1.
*/
ReferenceValue() : refs(1), weakRefs(1) {
/*
* Note the initial value of weakRefs -- there is a single implicit
* weak reference held by -all- strong references to the object; when all strong references are released,
* this weak reference is also released, allowing deallocation to occur.
*
* This approach allows us to avoid any ordering concerns around strong and weak reference behavior, at the cost
* of one additional atomic operation upon discarding the last strorng reference.
*/
}
/** Destroy the referenced value. */
~ReferenceValue() {
PLCF_ASSERT(refs == 0);
}
/* Alignment Note: These two values should align the concrete subclass' storage at either 8 or 16 bytes,
* depending on the target platform's size_t width. This should give us optimal layout on most platforms. */
/** This value's strong reference count; if this hits zero, the backing value should be destructed and/or deallocated. */
volatile size_t refs;
/** This value's weak reference count; if this hits zero, this containing ReferenceValue should be deallocated. */
volatile size_t weakRefs;
};
/**
* @internal
* An inline-allocated reference-counted value.
*
* @tparam T The type held by this referenced value.
*/
template <typename T> class InlineReferencedValue : public ReferenceValue<T> {
public:
/** Destroy the referenced value. */
~InlineReferencedValue () {}
/**
* Construct a new inline-allocated value.
*
* @param args The arguments with which an instance of @a T will be constructed.
* @tparam Args The @a T constructor's arguments types.
*/
template <class ...Args> InlineReferencedValue (Args&&... args) : _value(atl::forward<Args>(args)...) { }
/**
* Returns a pointer to the managed object.
*/
inline T* get (void) noexcept {
return &_value;
}
/**
* Destroy the backing object allocation.
*/
inline void destroy (void) {
_value.~T();
}
private:
/**
* Inline allocation of the reference counted value.
*
* We use a union to disable default destruction of the value; this allows us to perform destruction
* as soon as the strong reference count hits zero, even if weak references require that this
* enclosing InlineReferencedValue remain alive.
*/
union {
/** The actual value. */
T _value;
};
};
} /* namespace refcount */
PLCR_CPP_END_ASYNC_NS
/**
* @}
*/
#endif /* PLCRASH_ASYNC_REFERENCE_VALUE_H */

102
Source/async_stl.hpp Normal file
Просмотреть файл

@ -0,0 +1,102 @@
/*
* Copyright (c) 2015 Plausible Labs Cooperative, Inc.
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use,
* copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef PLCRASH_ASYNC_STL_HPP
#define PLCRASH_ASYNC_STL_HPP
#include "PLCrashMacros.h"
/**
* @internal
* @ingroup plcrash_async
* @defgroup plcrash_async_stl STL-compatible compile-time-only templates and type traits.
*
* A set of STL-compatible templates and type traits for use in contexts where dependency on the C++
* STL is not possible.
*
* @{
*/
PLCR_CPP_BEGIN_ASYNC_NS namespace atl {
/** Equivalent to C++11 std::nullptr_t */
typedef decltype(nullptr) nullptr_t;
/** Equivalent to C++11 std::integral_constant */
template <typename T, T Value> struct integral_constant {
static constexpr const T value = Value;
typedef T value_type;
typedef integral_constant type;
constexpr operator value_type() const noexcept {
return value;
}
};
/** Equivalent to C++17's std::bool_constant. */
template <bool B> using bool_constant = integral_constant<bool, B>;
/** Equivalent to C++11 std::false_type */
typedef integral_constant<bool, true> true_type;
/** Equivalent to C++11 std::false_type */
typedef integral_constant<bool, false> false_type;
/** Equivalent to C++11 std::conditional */
template <bool Cond, typename T, typename F> struct conditional { typedef T type; };
template <typename T, typename F> struct conditional<false, T, F> { typedef F type; };
/** Equivalent to C++11 std::is_lvalue_reference */
template <typename T> struct is_lvalue_reference : false_type {};
template <typename T> struct is_lvalue_reference<T&> : true_type {};
/** Equivalent to C++11 std::remove_reference */
template <typename R> struct remove_reference { typedef R type; };
template <typename R> struct remove_reference<R&> { typedef R type; };
template <typename R> struct remove_reference<R&&> { typedef R type; };
/** Equivalent to C++14 std::remove_reference_t */
template <typename T> using remove_reference_t = typename remove_reference<T>::type;
/* Equivalent to to C++14 std::forward */
template <typename T> constexpr T &&forward (remove_reference_t<T> &value) { return static_cast<T&&>(value); }
template <typename T> constexpr T &&forward (remove_reference_t<T> &&value) {
static_assert(!is_lvalue_reference<T>::value, "An rvalue reference can not be forwarded as an lvalue");
return static_cast<T&&>(value);
}
/* Equivalent to C++14 std::move */
template <typename T> constexpr remove_reference_t<T> &&move (T&& value) noexcept {
using V = remove_reference_t<T>;
return static_cast<V&&>(value);
};
} /* namespace atl */ PLCR_CPP_END_ASYNC_NS
/**
* @}
*/
#endif /* PLCRASH_ASYNC_STL_HPP */

274
Source/shared_ptr.hpp Executable file
Просмотреть файл

@ -0,0 +1,274 @@
/*
* Copyright (c) 2014 Plausible Labs Cooperative, Inc.
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use,
* copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef PLCRASH_ASYNC_SHARED_PTR_H
#define PLCRASH_ASYNC_SHARED_PTR_H
#include "Reference.hpp"
#include "PLCrashMacros.h"
#include "async_stl.hpp"
/**
* @internal
* @ingroup plcrash_async
*
* @{
*/
PLCR_CPP_BEGIN_ASYNC_NS
/* Forward-declare weak_ptr */
template <typename T> class weak_ptr;
/**
* The shared_ptr class holds a strong reference to a reference counted object.
*
* The object is destroyed when the last remaining shared_ptr is destroyed, or otherwise releases its ownership
* of the shared object.
*
* @tparam T The referenced object type.
*
* @par Thread Safety
*
* Reference counting is fully thread-safe, and multiple shared_ptr instances may reference the same shared object. A
* single shared_ptr instance, however, must not be concurrently mutated -- or accessed during mutation -- without
* external synchronization.
*/
template <typename T> class shared_ptr {
private:
/**
* Construct a new shared reference, assuming ownership of the @a value. The reference count of @a value will not
* be incremented.
*
* @param value The referenced value for the newly constructed shared reference, or NULL if the new shared
* reference should be empty.
*/
shared_ptr (refcount::InlineReferencedValue<T> *value) : _impl(value, false) { }
/* Mark weak_ptr as a friend to allow access to our backing _impl. */
friend class weak_ptr<T>;
/* Grant access to internal elements of other template instantiations */
template <typename U> friend class shared_ptr;
/* Type tag used to enable is_convertible constructor */
struct convertible_tag {};
public:
/**
* Construct an empty shared reference.
*/
constexpr shared_ptr () noexcept { }
/**
* Construct a shared reference by atomically acquiring a strong reference to an existing shared_ptr<>T>
*/
shared_ptr (const shared_ptr<T> &other) = default;
/**
* Construct a shared reference by atomically moving a strong reference from an existing shared_ptr<>T>
*/
shared_ptr (shared_ptr<T> &&other) = default;
/**
* Copy assignment.
*/
shared_ptr &operator= (const shared_ptr<T> &other) = default;
/**
* Move assignment.
*/
shared_ptr &operator= (shared_ptr<T> &&other) = default;
/**
* Construct a shared reference by atomically acquiring a strong reference to an existing weak_ptr<T>.
*
* If a strong reference to the reference counted object can not be acquired, the new strong reference will be empty.
*/
shared_ptr (const weak_ptr<T> &weak) {
/* Fetch the backing shared value. If the value is NULL, the weakptr is empty. */
auto v = weak._impl.sharedValue();
if (v == nullptr) {
return;
}
/* Atomically increment the reference count using compare-and-swap to ensure that it hasn't changed since we
* fetched its value. We know that the sharedValue itself won't be deallocated, as the weak_ptr reference
* we've been given will keep it alive. */
int64_t refCount;
do {
/* If the strong reference count is already zero, the object is dead, and we're done. */
refCount = v->refs;
if (refCount == 0)
return;
/* Loop until we successfully swap in the new value. */
} while (!__sync_bool_compare_and_swap(&v->refs, refCount, refCount+1));
/* If we managed to get here, we now own a strong reference; insert it into our backing Reference instance,
* letting it adopt our acquired strong reference. */
_impl.put(v, false);
}
/**
* Construct a new shared reference wrapping a newly constructed instance of @a T, using @a args as the parameter
* list for the constructor of @a T.
*
* @param args The arguments with which an instance of @a T will be constructed.
*/
template <class ...Args> static shared_ptr<T> make_shared(Args&&... args) {
refcount::InlineReferencedValue<T> *s = new refcount::InlineReferencedValue<T>(atl::forward<Args>(args)...);
return shared_ptr<T>(s);
}
/**
* Return true if this reference is empty.
*
* @note An empty reference is equivalent to a reference to a null pointer.
*/
inline bool isEmpty (void) const {
return _impl.isEmpty();
}
/**
* Return true if this reference is *not* empty.
*
* @note An empty reference is equivalent to a reference to a null pointer.
*
* This is suitable for use in conditional expressions, for example:
* @code
if (ptr) {
...
}
@endcode
*/
inline operator bool () const {
return !isEmpty();
}
/**
* Return the current strong reference count for the managed object, or 0 if there is no managed object. The
* reference count should be equal to the number of shared_ptr instances referencing the managed object.
*
* @warning The reference count is not a reliable indicator of object lifetime or liveness, and should not be used
* outside of testing or debugging.
*/
inline size_t referenceCount (void) const {
return _impl.referenceCount();
}
inline size_t use_count (void) const {
return referenceCount();
}
/** Returns a pointer to the managed object. */
inline T* get (void) const {
return _impl.get();
}
/** Dereferences the pointer to the managed object */
inline T& operator *() const {
return *_impl.get();
}
/** Dereferences the pointer to the managed object */
inline T* operator ->() const {
return _impl.get();
}
/** Release ownership of the managed object, if any. Upon return, the shared reference will be empty. */
inline void clear () {
_impl.clear();
}
private:
/** Reference implementation */
refcount::Reference<T, refcount::InlineReferencedValue<T>, refcount::StrongReferenceType<T, refcount::InlineReferencedValue<T>>> _impl;
};
/**
* Construct an object of type @a T and wraps it in a reference counting shared_ptr, using @a args
* as the parameter list for the constructor of @a T.
*
* @param args The arguments with which an instance of @a T will be constructed.
*
* @tparam T The object type.
*/
template <class T, class ...Args> shared_ptr<T> make_shared (Args&&... args) {
return shared_ptr<T>::make_shared(atl::forward<Args>(args)...);
};
/**
* Compare two shared references, returning true if the referenced objects are equal.
*/
template <class T, class U> inline bool operator== (const shared_ptr<T> &ptr1, const shared_ptr<U> &ptr2) {
return ptr1.get() == ptr2.get();
}
/**
* Compare two shared references, returning true if the referenced objects are not equal.
*/
template <class T, class U> inline bool operator!= (const shared_ptr<T> &ptr1, const shared_ptr<U> &ptr2) {
return !(ptr1 == ptr2);
}
/**
* Compare a shared reference to a pointer, returning true if the referenced objects are equal.
*/
template <class T> inline bool operator== (const shared_ptr<T> &ptr, atl::nullptr_t) {
return ptr.isEmpty();
}
/**
* Compare a shared reference to a pointer, returning true if the referenced objects are equal.
*/
template <class U> inline bool operator== (atl::nullptr_t, const shared_ptr<U> &ptr) {
return ptr.isEmpty();
}
/**
* Compare a shared reference to a pointer, returning true if the referenced objects are not equal.
*/
template <class T> inline bool operator!= (const shared_ptr<T> &ptr, atl::nullptr_t) {
return !ptr.isEmpty();
}
/**
* Compare a shared reference to a pointer, returning true if the referenced objects are not equal.
*/
template <class U> inline bool operator!= (atl::nullptr_t, const shared_ptr<U> &ptr) {
return !ptr.isEmpty();
}
PLCR_CPP_END_ASYNC_NS
/**
* @}
*/
#endif /* PLCRASH_ASYNC_SHARED_PTR_H */

256
Source/shared_ptr_test.cpp Normal file
Просмотреть файл

@ -0,0 +1,256 @@
/*
* Copyright (c) 2014 - 2015 Plausible Labs Cooperative, Inc.
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use,
* copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
#include "shared_ptr.hpp"
#include "weak_ptr.hpp"
#include "PLCrashCatchTest.hpp"
PLCR_CPP_BEGIN_ASYNC_NS
TEST_CASE("Shared References") {
WHEN("Wrapping primitive types") {
auto ptr = make_shared<int>(42);
THEN("Primitive value should be dereferenceable by value and pointer-to-value") {
REQUIRE(*ptr == 42);
REQUIRE(*(ptr.get()) == 42);
}
}
WHEN("Wrapping C++ types") {
/* Verify all dereferencing styles work on classes */
class ExampleClass {
public:
int val;
ExampleClass (int v) : val(v) { }
};
auto ptr = make_shared<ExampleClass>(42);
THEN("Object value should be dereferenceable by value and pointer-to-value") {
REQUIRE((*ptr).val == 42);
REQUIRE((ptr.get())->val == 42);
REQUIRE(ptr->val == 42);
}
THEN("Reference should not be empty") {
REQUIRE(!ptr.isEmpty());
}
}
WHEN("Operating on an empty shared reference") {
shared_ptr<int> ptr;
THEN("Retain count should be 0") {
REQUIRE(ptr.referenceCount() == 0);
}
THEN("Reference should be empty") {
REQUIRE(ptr.isEmpty());
}
THEN("Retain count should be 1 once a value is set") {
ptr = make_shared<int>(42);
REQUIRE(ptr.referenceCount() == 1);
}
THEN("Returned reference should be null") {
REQUIRE(ptr.get() == nullptr);
}
}
WHEN("Copying shared references") {
auto ptr = make_shared<int>(42);
THEN("Retain count should start at 1") {
REQUIRE(ptr.referenceCount() == 1);
}
THEN("Retain count should increase after copy construction") {
auto copiedPtr = ptr;
REQUIRE(copiedPtr.referenceCount() == 2);
REQUIRE(ptr.referenceCount() == 2);
}
THEN("Retain count should increase after copy assignment") {
shared_ptr<int> copiedPtr;
copiedPtr = ptr;
REQUIRE(copiedPtr.referenceCount() == 2);
REQUIRE(ptr.referenceCount() == 2);
}
}
WHEN("Moving shared references") {
THEN("Retain count should remain constant after move construction") {
shared_ptr<int> ptr(atl::move(make_shared<int>(42)));
REQUIRE(ptr.referenceCount() == 1);
}
THEN("Retain count should remain constant after move assignment") {
shared_ptr<int> ptr;
ptr = make_shared<int>(42);
REQUIRE(ptr.referenceCount() == 1);
}
}
WHEN("Clearing shared references") {
auto ptr = make_shared<int>(42);
THEN("The reference should be empty after clear()") {
REQUIRE(ptr.referenceCount() == 1);
REQUIRE(!ptr.isEmpty());
ptr.clear();
REQUIRE(ptr.referenceCount() == 0);
REQUIRE(ptr.isEmpty());
}
}
WHEN("Constructing from weak references") {
THEN("empty weak references should return empty strong references") {
weak_ptr<int> wptr;
shared_ptr<int> sptr = wptr;
REQUIRE(sptr.isEmpty());
}
THEN("live weak references should return live strong references") {
auto sptr1 = make_shared<int>(42);
weak_ptr<int> wptr(sptr1);
/* New strong pointer must be non-empty */
auto sptr2 = shared_ptr<int>(wptr);
REQUIRE(!sptr2.isEmpty());
/* Reference count should now be 2 */
REQUIRE(sptr2.referenceCount() == 2);
REQUIRE(sptr1.referenceCount() == sptr2.referenceCount());
/* Value dereferencing should actually work */
REQUIRE(*sptr2 == 42);
REQUIRE(*sptr2 == *sptr1);
}
THEN("dead weak references should return empty strong references") {
weak_ptr<int> wptr;
/* Use a block scope to control the strong ptr's lifetime. */
{
auto sptr = make_shared<int>(42);
wptr = sptr;
REQUIRE(sptr.referenceCount() == 1);
}
/* Weak pointer should now point to a dead value. */
REQUIRE(wptr.referenceCount() == 0);
/* The strong pointer should detect the zero refcount and return an empty strong pointer */
shared_ptr<int> sptr = wptr;
REQUIRE(sptr.isEmpty());
}
}
WHEN("Destroying a shared reference") {
class ExampleClass {
public:
ExampleClass (size_t *destCount) : _destCount(destCount) {}
~ExampleClass () {
*_destCount = *_destCount + 1;
}
private:
size_t *_destCount;
};
THEN("The managed object's destructor should be executed once (and only once)") {
/* Tracks the number of times ExampleClass' destructor was invoked. */
size_t destCount = 0;
/* Use a block scope to control the ptr's lifetime. */
{
auto ptr = make_shared<ExampleClass>(&destCount);
REQUIRE(destCount == 0);
REQUIRE(ptr.referenceCount() == 1);
}
/** Assert that the destructor was called once and only once */
REQUIRE(destCount == 1);
}
}
WHEN("Comparing empty shared references") {
shared_ptr<int> ref;
THEN("empty references should have a bool value of false") {
REQUIRE(!ref);
}
THEN("empty references should be equal") {
shared_ptr<int> ref2;
REQUIRE(ref == ref2);
}
THEN("empty references should compare as equal to nullptr") {
class ExampleClass {};
REQUIRE(ref == nullptr);
REQUIRE(nullptr == ref); // Compare both forms of the overload
}
THEN("empty references should not be equal to non-empty references") {
auto nonempty = make_shared<int>(42);
REQUIRE(ref != nonempty);
}
}
WHEN("Comparing non-empty shared references") {
auto ref = make_shared<int>(42);
THEN("non-empty references should have a bool value of true") {
REQUIRE(ref);
}
THEN("non-empty references should be equal if their pointer values are equal") {
/* Point at different values, will not be equal */
auto refNEQ = make_shared<int>(42);
REQUIRE(refNEQ != ref);
/* Point at the same value, will be equal */
auto refEQ = ref;
REQUIRE(ref == refEQ);
}
THEN("non-empty references should not compare as equal to nullptr") {
REQUIRE(ref != nullptr);
REQUIRE(nullptr != ref); // Compare both forms of the overload
}
THEN("non-empty references should not be equal to empty references") {
shared_ptr<int> empty;
REQUIRE(ref != empty);
}
}
}
PLCR_CPP_END_ASYNC_NS

112
Source/weak_ptr.hpp Normal file
Просмотреть файл

@ -0,0 +1,112 @@
/*
* Copyright (c) 2014 Plausible Labs Cooperative, Inc.
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use,
* copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef PLCRASH_ASYNC_WEAK_PTR_H
#define PLCRASH_ASYNC_WEAK_PTR_H
#include "PLCrashMacros.h"
#include "Reference.hpp"
/**
* @internal
* @ingroup plcrash_async
*
* @{
*/
PLCR_CPP_BEGIN_ASYNC_NS
/* Forward-declare shared_ptr */
template <typename T> class shared_ptr;
/**
* The weak_ptr class holds a weak reference to a reference counted object.
*
* A weak_ptr may be atomically converted to a strong shared_ptr, if a strong reference to the managed object can be acquired.
*
* @tparam T The referenced object type.
*
* @par Thread Safety
*
* Reference counting is fully thread-safe, and multiple weak_ptr instances may reference the same object. A single
* weak_ptr instance, however, must not be concurrently mutated -- or accessed during mutation -- without
* external synchronization.
*/
template <typename T> class weak_ptr {
private:
/* Mark shared_ptr as a friend to allow access to our backing _impl. */
friend class shared_ptr<T>;
public:
/**
* Construct an empty weak reference.
*/
constexpr weak_ptr () noexcept { }
/**
* Construct a weak reference to the object managed by @a ref.
*
* @param ref A strong reference to an object of type `T`.
*/
weak_ptr (const shared_ptr<T> &ref) : _impl(ref._impl.sharedValue(), true) {}
/**
* Atomically acquire and return a strong reference. If a strong reference to the reference counted object can not
* be acquired, the returned strong reference will be empty.
*/
shared_ptr<T> strongReference () {
return shared_ptr<T>(*this);
}
/**
* Return the current strong reference count for the managed object, or 0 if there is no managed object. The
* reference count should be equivalent to the number of shared_ptr instances managing the current object.
*
* @warning The reference count is not a reliable indicator of object lifetime or liveness, and should not be used
* outside of testing or debugging.
*/
size_t referenceCount (void) const {
return _impl.referenceCount();
}
/** Release ownership of the managed object, if any. Upon return, the weak reference will be empty. */
inline void clear () {
_impl.clear();
}
private:
/** Reference implementation */
refcount::Reference<T, refcount::InlineReferencedValue<T>, refcount::WeakReferenceType<T, refcount::InlineReferencedValue<T>>> _impl;
};
PLCR_CPP_END_ASYNC_NS
/**
* @}
*/
#endif /* PLCRASH_ASYNC_WEAK_PTR_H */

129
Source/weak_ptr_test.cpp Normal file
Просмотреть файл

@ -0,0 +1,129 @@
/*
* Copyright (c) 2014 Plausible Labs Cooperative, Inc.
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use,
* copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
#include "shared_ptr.hpp"
#include "weak_ptr.hpp"
#include "PLCrashCatchTest.hpp"
PLCR_CPP_BEGIN_ASYNC_NS
TEST_CASE("Weak References") {
WHEN("Operating on an empty shared reference") {
weak_ptr<int> wptr;
THEN("Retain count should be 0") {
REQUIRE(wptr.referenceCount() == 0);
}
THEN("Retain count should be 1 once a value is set") {
auto strong = make_shared<int>(42);
wptr = strong;
REQUIRE(wptr.referenceCount() == 1);
}
THEN("Retain count should be 0 after the strong reference goes out of scope") {
REQUIRE(wptr.referenceCount() == 0);
{
auto strong = make_shared<int>(42);
wptr = strong;
REQUIRE(wptr.referenceCount() == 1);
}
REQUIRE(wptr.referenceCount() == 0);
}
}
WHEN("Constructing from an existing strong reference") {
THEN("Strong reference count should not increase when constructing the weak reference") {
auto ptr = make_shared<int>(42);
REQUIRE(ptr.referenceCount() == 1);
auto wptr = weak_ptr<int>(ptr);
REQUIRE(ptr.referenceCount() == 1);
REQUIRE(wptr.referenceCount() == ptr.referenceCount());
}
THEN("Retain count should be 0 after the strong reference goes out of scope") {
weak_ptr<int> *wptr = NULL;
{
auto ptr = make_shared<int>(42);
wptr = new weak_ptr<int>(ptr);
REQUIRE(ptr.referenceCount() == 1);
}
REQUIRE(wptr->referenceCount() == 0);
delete wptr;
}
}
WHEN("Destroying a weak reference") {
class ExampleClass {
public:
ExampleClass (size_t *destCount) : _destCount(destCount) {}
~ExampleClass () {
*_destCount = *_destCount + 1;
}
private:
size_t *_destCount;
};
THEN("The managed object's destructor should be executed once (and only once) when only a weak reference remains") {
/* Tracks the number of times ExampleClass' destructor was invoked. */
size_t destCount = 0;
/* Use block scopes to control the weak and strong reference's lifetime. */
{
weak_ptr<ExampleClass> wptr;
{
auto ptr = make_shared<ExampleClass>(&destCount);
wptr = ptr;
REQUIRE(destCount == 0);
REQUIRE(ptr.referenceCount() == 1);
}
/** Assert that the destructor was called once and only once after the strong reference went out-of-scope. */
REQUIRE(destCount == 1);
}
/** Assert that the destructor was not called again after the weak reference went out-of-scope. */
REQUIRE(destCount == 1);
}
}
WHEN("Converting to a strong reference") {
/* The actual conversion behavior is implemented and tested in shared_ptr; this is just a smoke test */
THEN("a weak reference must a strong reference") {
auto sptr = make_shared<int>(42);
weak_ptr<int> ref = sptr;
/* Try creating a strong reference */
auto sptr2 = ref.strongReference();
REQUIRE(sptr2.referenceCount() == 2);
REQUIRE(sptr.referenceCount() == sptr2.referenceCount());
}
}
}
PLCR_CPP_END_ASYNC_NS