aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore1
-rw-r--r--Taskfile.yaml4
-rw-r--r--lib/Hashing.Portable/LICENSE (renamed from lib/Hashing.Portable/LICENSE.txt)2
-rw-r--r--lib/Hashing.Portable/build.readme.txt (renamed from lib/Hashing.Portable/build.readme.md)0
-rw-r--r--lib/Hashing.Portable/src/VNLib.Hashing.Portable.csproj2
-rw-r--r--lib/Net.Compression/LICENSE (renamed from lib/Net.Compression/LICENSE.txt)0
-rw-r--r--lib/Net.Compression/build.readme.txt (renamed from lib/Net.Compression/build.readme.md)0
-rw-r--r--lib/Net.Compression/vnlib_compress/compression.c6
-rw-r--r--lib/Net.Compression/vnlib_compress/feature_brotli.c4
-rw-r--r--lib/Net.Compression/vnlib_compress/feature_brotli.h4
-rw-r--r--lib/Net.Compression/vnlib_compress/feature_zlib.c4
-rw-r--r--lib/Net.Compression/vnlib_compress/feature_zlib.h4
-rw-r--r--lib/Net.Http/LICENSE (renamed from lib/Plugins.Essentials.ServiceStack/LICENSE.txt)4
-rw-r--r--lib/Net.Http/build.readme.txt (renamed from lib/Net.Http/build.readme.md)0
-rw-r--r--lib/Net.Http/src/VNLib.Net.Http.csproj2
-rw-r--r--lib/Net.Messaging.FBM/LICENSE (renamed from lib/Net.Http/LICENSE.txt)4
-rw-r--r--lib/Net.Messaging.FBM/build.readme.txt (renamed from lib/Net.Messaging.FBM/build.readme.md)0
-rw-r--r--lib/Net.Messaging.FBM/src/VNLib.Net.Messaging.FBM.csproj2
-rw-r--r--lib/Net.Rest.Client/LICENSE (renamed from lib/Plugins/LICENSE.txt)7
-rw-r--r--lib/Net.Rest.Client/build.readme.txt (renamed from lib/Net.Rest.Client/build.readme.md)0
-rw-r--r--lib/Net.Rest.Client/src/VNLib.Net.Rest.Client.csproj6
-rw-r--r--lib/Net.Transport.SimpleTCP/LICENSE (renamed from lib/Net.Messaging.FBM/LICENSE.txt)4
-rw-r--r--lib/Net.Transport.SimpleTCP/build.readme.txt (renamed from lib/Net.Transport.SimpleTCP/build.readme.md)0
-rw-r--r--lib/Net.Transport.SimpleTCP/src/VNLib.Net.Transport.SimpleTCP.csproj2
-rw-r--r--lib/Plugins.Essentials.ServiceStack/LICENSE (renamed from lib/Net.Transport.SimpleTCP/LICENSE.txt)4
-rw-r--r--lib/Plugins.Essentials.ServiceStack/README.md71
-rw-r--r--lib/Plugins.Essentials.ServiceStack/build.readme.txt (renamed from lib/Plugins.Essentials.ServiceStack/build.readme.md)0
-rw-r--r--lib/Plugins.Essentials.ServiceStack/src/Construction/HttpServiceStackBuilder.cs (renamed from lib/Plugins.Essentials.ServiceStack/src/HttpServiceStackBuilder.cs)8
-rw-r--r--lib/Plugins.Essentials.ServiceStack/src/Construction/IAccountSecUpdateable.cs (renamed from lib/Plugins.Essentials.ServiceStack/src/IAccountSecUpdateable.cs)2
-rw-r--r--lib/Plugins.Essentials.ServiceStack/src/Construction/IDomainBuilder.cs (renamed from lib/Plugins.Essentials.ServiceStack/src/IDomainBuilder.cs)2
-rw-r--r--lib/Plugins.Essentials.ServiceStack/src/Construction/IVirtualHostBuilder.cs (renamed from lib/Plugins.Essentials.ServiceStack/src/IVirtualHostBuilder.cs)2
-rw-r--r--lib/Plugins.Essentials.ServiceStack/src/Construction/IVirtualHostHooks.cs (renamed from lib/Plugins.Essentials.ServiceStack/src/IVirtualHostHooks.cs)2
-rw-r--r--lib/Plugins.Essentials.ServiceStack/src/Construction/SsBuilderExtensions.cs (renamed from lib/Plugins.Essentials.ServiceStack/src/SsBuilderExtensions.cs)25
-rw-r--r--lib/Plugins.Essentials.ServiceStack/src/Construction/VirtualHostConfiguration.cs (renamed from lib/Plugins.Essentials.ServiceStack/src/VirtualHostConfiguration.cs)6
-rw-r--r--lib/Plugins.Essentials.ServiceStack/src/IHttpPluginManager.cs (renamed from lib/Plugins.Essentials.ServiceStack/src/IPluginController.cs)0
-rw-r--r--lib/Plugins.Essentials.ServiceStack/src/VNLib.Plugins.Essentials.ServiceStack.csproj2
-rw-r--r--lib/Plugins.Essentials/LICENSE195
-rw-r--r--lib/Plugins.Essentials/LICENSE.txt195
-rw-r--r--lib/Plugins.Essentials/build.readme.txt (renamed from lib/Plugins.Essentials/build.readme.md)0
-rw-r--r--lib/Plugins.Essentials/src/VNLib.Plugins.Essentials.csproj2
-rw-r--r--lib/Plugins.PluginBase/LICENSE195
-rw-r--r--lib/Plugins.PluginBase/LICENSE.txt195
-rw-r--r--lib/Plugins.PluginBase/build.readme (renamed from lib/Plugins.PluginBase/build.readme.md)0
-rw-r--r--lib/Plugins.PluginBase/src/VNLib.Plugins.PluginBase.csproj2
-rw-r--r--lib/Plugins.Runtime/LICENSE (renamed from lib/NativeHeapApi/LICENSE.txt)0
-rw-r--r--lib/Plugins.Runtime/README.md79
-rw-r--r--lib/Plugins.Runtime/build.readme.txt (renamed from lib/Plugins.Runtime/build.readme.md)0
-rw-r--r--lib/Plugins.Runtime/src/VNLib.Plugins.Runtime.csproj2
-rw-r--r--lib/Plugins/LICENSE (renamed from lib/Net.Rest.Client/LICENSE.txt)0
-rw-r--r--lib/Plugins/build.readme.txt (renamed from lib/Plugins/build.readme.md)0
-rw-r--r--lib/Plugins/src/VNLib.Plugins.csproj2
-rw-r--r--lib/Utils.Memory/NativeHeapApi/LICENSE (renamed from lib/Plugins.Runtime/LICENSE.txt)0
-rw-r--r--lib/Utils.Memory/NativeHeapApi/README.md (renamed from lib/NativeHeapApi/README.md)0
-rw-r--r--lib/Utils.Memory/NativeHeapApi/src/NativeHeapApi.h (renamed from lib/NativeHeapApi/src/NativeHeapApi.h)2
-rw-r--r--lib/Utils.Memory/vnlib_rpmalloc/CMakeLists.txt142
-rw-r--r--lib/Utils.Memory/vnlib_rpmalloc/LICENSE (renamed from lib/Utils/LICENSE.txt)4
-rw-r--r--lib/Utils.Memory/vnlib_rpmalloc/Taskfile.yaml73
-rw-r--r--lib/Utils.Memory/vnlib_rpmalloc/build.readme.txt (renamed from lib/Utils/build.readme.md)0
-rw-r--r--lib/Utils.Memory/vnlib_rpmalloc/package.json10
-rw-r--r--lib/Utils.Memory/vnlib_rpmalloc/vnlib_rpmalloc.c (renamed from lib/WinRpMalloc/src/dllmain.c)104
-rw-r--r--lib/Utils.Memory/vnlib_rpmalloc/vnlib_rpmalloc.h11
-rw-r--r--lib/Utils.Memory/vnlib_rpmalloc/vnlib_rpmalloc.vcxitems31
-rw-r--r--lib/Utils/LICENSE (renamed from lib/WinRpMalloc/LICENSE.txt)69
-rw-r--r--lib/Utils/build.readme.txt (renamed from lib/WinRpMalloc/build.readme.md)0
-rw-r--r--lib/Utils/src/VNLib.Utils.csproj2
-rw-r--r--lib/WinRpMalloc/README.md16
-rw-r--r--lib/WinRpMalloc/Taskfile.yaml73
-rw-r--r--lib/WinRpMalloc/src/WinRpMalloc.vcxproj177
-rw-r--r--lib/WinRpMalloc/src/framework.h29
-rw-r--r--lib/WinRpMalloc/src/package.json9
-rw-r--r--lib/WinRpMalloc/src/pch.c5
-rw-r--r--lib/WinRpMalloc/src/pch.h55
-rw-r--r--lib/WinRpMalloc/src/rpmalloc.c3616
-rw-r--r--lib/WinRpMalloc/src/rpmalloc.h369
74 files changed, 813 insertions, 5037 deletions
diff --git a/.gitignore b/.gitignore
index 3a794dc..7221540 100644
--- a/.gitignore
+++ b/.gitignore
@@ -364,3 +364,4 @@ MigrationBackup/
*.filters
/lib/Net.Compression/vnlib_compress/build
+/lib/Utils.Memory/vnlib_rpmalloc/build
diff --git a/Taskfile.yaml b/Taskfile.yaml
index 2f12d1f..6cd1f0d 100644
--- a/Taskfile.yaml
+++ b/Taskfile.yaml
@@ -51,8 +51,8 @@ tasks:
cmds:
#copy license and readme to target
- - cd .. && powershell -Command "Copy-Item -Path ./LICENSE.txt -Destination '{{.BUILD_OUT}}/license.txt'"
- - cd .. && powershell -Command "Copy-Item -Path ./build.readme.md -Destination '{{.BUILD_OUT}}/readme.md'"
+ - cd .. && powershell -Command "Copy-Item -Path ./LICENSE -Destination '{{.BUILD_OUT}}/license.txt'"
+ - cd .. && powershell -Command "Copy-Item -Path ./build.readme.txt -Destination '{{.BUILD_OUT}}/readme.md'"
#tar outputs
- cd "{{.BUILD_OUT}}" && tar -czf "{{.TARGET}}/{{.BUILD_MODE}}.tgz" .
diff --git a/lib/Hashing.Portable/LICENSE.txt b/lib/Hashing.Portable/LICENSE
index 895db28..0b55ddb 100644
--- a/lib/Hashing.Portable/LICENSE.txt
+++ b/lib/Hashing.Portable/LICENSE
@@ -2,7 +2,7 @@ Copyright (c) 2022 Vaughn Nugent
Contact information
Name: Vaughn Nugent
- Email: public[at]vaughnnugent[dot]com
+ Email: vnpublic[at]proton.me
Website: https://www.vaughnnugent.com
The software in this repository is licensed under the GNU GPL version 2.0 (or any later version).
diff --git a/lib/Hashing.Portable/build.readme.md b/lib/Hashing.Portable/build.readme.txt
index e69de29..e69de29 100644
--- a/lib/Hashing.Portable/build.readme.md
+++ b/lib/Hashing.Portable/build.readme.txt
diff --git a/lib/Hashing.Portable/src/VNLib.Hashing.Portable.csproj b/lib/Hashing.Portable/src/VNLib.Hashing.Portable.csproj
index a1000c9..21efb3f 100644
--- a/lib/Hashing.Portable/src/VNLib.Hashing.Portable.csproj
+++ b/lib/Hashing.Portable/src/VNLib.Hashing.Portable.csproj
@@ -38,7 +38,7 @@
<Pack>True</Pack>
<PackagePath>\</PackagePath>
</None>
- <None Include="..\LICENSE.txt">
+ <None Include="..\LICENSE">
<Pack>True</Pack>
<PackagePath>\</PackagePath>
</None>
diff --git a/lib/Net.Compression/LICENSE.txt b/lib/Net.Compression/LICENSE
index 8a2d49d..8a2d49d 100644
--- a/lib/Net.Compression/LICENSE.txt
+++ b/lib/Net.Compression/LICENSE
diff --git a/lib/Net.Compression/build.readme.md b/lib/Net.Compression/build.readme.txt
index e69de29..e69de29 100644
--- a/lib/Net.Compression/build.readme.md
+++ b/lib/Net.Compression/build.readme.txt
diff --git a/lib/Net.Compression/vnlib_compress/compression.c b/lib/Net.Compression/vnlib_compress/compression.c
index 0d57096..dc681c4 100644
--- a/lib/Net.Compression/vnlib_compress/compression.c
+++ b/lib/Net.Compression/vnlib_compress/compression.c
@@ -214,7 +214,7 @@ VNLIB_EXPORT void* VNLIB_CC AllocateCompressor(CompressorType type, CompressionL
}
}
-VNLIB_EXPORT int VNLIB_CC FreeCompressor(_In_ void* compressor)
+VNLIB_EXPORT int VNLIB_CC FreeCompressor(_In_ const void* compressor)
{
CompressorState* comp;
int errorCode;
@@ -273,7 +273,7 @@ VNLIB_EXPORT int VNLIB_CC FreeCompressor(_In_ void* compressor)
return errorCode;
}
-VNLIB_EXPORT int64_t VNLIB_CC GetCompressedSize(_In_ void* compressor, uint64_t inputLength, int32_t flush)
+VNLIB_EXPORT int64_t VNLIB_CC GetCompressedSize(_In_ const void* compressor, uint64_t inputLength, int32_t flush)
{
CompressorState* comp;
int64_t result;
@@ -331,7 +331,7 @@ VNLIB_EXPORT int64_t VNLIB_CC GetCompressedSize(_In_ void* compressor, uint64_t
* indicate failure.
* @param compressor
*/
-VNLIB_EXPORT int VNLIB_CC CompressBlock(_In_ void* compressor, CompressionOperation* operation)
+VNLIB_EXPORT int VNLIB_CC CompressBlock(_In_ const void* compressor, CompressionOperation* operation)
{
int result;
CompressorState* comp;
diff --git a/lib/Net.Compression/vnlib_compress/feature_brotli.c b/lib/Net.Compression/vnlib_compress/feature_brotli.c
index f528cf1..752082a 100644
--- a/lib/Net.Compression/vnlib_compress/feature_brotli.c
+++ b/lib/Net.Compression/vnlib_compress/feature_brotli.c
@@ -107,7 +107,7 @@ void BrFreeCompressor(CompressorState* state)
}
}
-int BrCompressBlock(CompressorState* state, CompressionOperation* operation)
+int BrCompressBlock(const CompressorState* state, CompressionOperation* operation)
{
BrotliEncoderOperation brOperation;
BROTLI_BOOL brResult;
@@ -192,7 +192,7 @@ int BrCompressBlock(CompressorState* state, CompressionOperation* operation)
}
-int64_t BrGetCompressedSize(CompressorState* state, uint64_t length)
+int64_t BrGetCompressedSize(const CompressorState* state, uint64_t length)
{
/*
* When the flush flag is set, the caller is requesting the
diff --git a/lib/Net.Compression/vnlib_compress/feature_brotli.h b/lib/Net.Compression/vnlib_compress/feature_brotli.h
index e04ce7a..b3cb35f 100644
--- a/lib/Net.Compression/vnlib_compress/feature_brotli.h
+++ b/lib/Net.Compression/vnlib_compress/feature_brotli.h
@@ -39,8 +39,8 @@ int BrAllocCompressor(CompressorState* state);
void BrFreeCompressor(CompressorState* state);
-int BrCompressBlock(CompressorState* state, CompressionOperation* operation);
+int BrCompressBlock(const CompressorState* state, CompressionOperation* operation);
-int64_t BrGetCompressedSize(CompressorState* state, uint64_t length);
+int64_t BrGetCompressedSize(const CompressorState* state, uint64_t length);
#endif /* !BROTLI_STUB_H_ */ \ No newline at end of file
diff --git a/lib/Net.Compression/vnlib_compress/feature_zlib.c b/lib/Net.Compression/vnlib_compress/feature_zlib.c
index 3dc2e3e..432b860 100644
--- a/lib/Net.Compression/vnlib_compress/feature_zlib.c
+++ b/lib/Net.Compression/vnlib_compress/feature_zlib.c
@@ -168,7 +168,7 @@ int DeflateFreeCompressor(CompressorState* state)
return TRUE;
}
-int DeflateCompressBlock(CompressorState* state, CompressionOperation* operation)
+int DeflateCompressBlock(const CompressorState* state, CompressionOperation* operation)
{
z_stream* stream;
int result;
@@ -243,7 +243,7 @@ int DeflateCompressBlock(CompressorState* state, CompressionOperation* operation
return result;
}
-int64_t DeflateGetCompressedSize(CompressorState* state, uint64_t length, int32_t flush)
+int64_t DeflateGetCompressedSize(const CompressorState* state, uint64_t length, int32_t flush)
{
uint64_t compressedSize;
diff --git a/lib/Net.Compression/vnlib_compress/feature_zlib.h b/lib/Net.Compression/vnlib_compress/feature_zlib.h
index 7db456c..2544d25 100644
--- a/lib/Net.Compression/vnlib_compress/feature_zlib.h
+++ b/lib/Net.Compression/vnlib_compress/feature_zlib.h
@@ -43,8 +43,8 @@ int DeflateAllocCompressor(CompressorState* state);
int DeflateFreeCompressor(CompressorState* state);
-int DeflateCompressBlock(CompressorState* state, CompressionOperation* operation);
+int DeflateCompressBlock(const CompressorState* state, CompressionOperation* operation);
-int64_t DeflateGetCompressedSize(CompressorState* state, uint64_t length, int32_t flush);
+int64_t DeflateGetCompressedSize(const CompressorState* state, uint64_t length, int32_t flush);
#endif
diff --git a/lib/Plugins.Essentials.ServiceStack/LICENSE.txt b/lib/Net.Http/LICENSE
index 147bcd6..982df24 100644
--- a/lib/Plugins.Essentials.ServiceStack/LICENSE.txt
+++ b/lib/Net.Http/LICENSE
@@ -1,8 +1,8 @@
-Copyright (c) 2022 Vaughn Nugent
+Copyright (c) 2023 Vaughn Nugent
Contact information
Name: Vaughn Nugent
- Email: public[at]vaughnnugent[dot]com
+ Email: vnpublic[at]proton.me
Website: https://www.vaughnnugent.com
The software in this repository is licensed under the GNU Affero GPL version 3.0 (or any later version).
diff --git a/lib/Net.Http/build.readme.md b/lib/Net.Http/build.readme.txt
index e69de29..e69de29 100644
--- a/lib/Net.Http/build.readme.md
+++ b/lib/Net.Http/build.readme.txt
diff --git a/lib/Net.Http/src/VNLib.Net.Http.csproj b/lib/Net.Http/src/VNLib.Net.Http.csproj
index 30f0439..729fc10 100644
--- a/lib/Net.Http/src/VNLib.Net.Http.csproj
+++ b/lib/Net.Http/src/VNLib.Net.Http.csproj
@@ -58,7 +58,7 @@
<Pack>True</Pack>
<PackagePath>\</PackagePath>
</None>
- <None Include="..\LICENSE.txt">
+ <None Include="..\LICENSE">
<Pack>True</Pack>
<PackagePath>\</PackagePath>
</None>
diff --git a/lib/Net.Http/LICENSE.txt b/lib/Net.Messaging.FBM/LICENSE
index 147bcd6..982df24 100644
--- a/lib/Net.Http/LICENSE.txt
+++ b/lib/Net.Messaging.FBM/LICENSE
@@ -1,8 +1,8 @@
-Copyright (c) 2022 Vaughn Nugent
+Copyright (c) 2023 Vaughn Nugent
Contact information
Name: Vaughn Nugent
- Email: public[at]vaughnnugent[dot]com
+ Email: vnpublic[at]proton.me
Website: https://www.vaughnnugent.com
The software in this repository is licensed under the GNU Affero GPL version 3.0 (or any later version).
diff --git a/lib/Net.Messaging.FBM/build.readme.md b/lib/Net.Messaging.FBM/build.readme.txt
index e69de29..e69de29 100644
--- a/lib/Net.Messaging.FBM/build.readme.md
+++ b/lib/Net.Messaging.FBM/build.readme.txt
diff --git a/lib/Net.Messaging.FBM/src/VNLib.Net.Messaging.FBM.csproj b/lib/Net.Messaging.FBM/src/VNLib.Net.Messaging.FBM.csproj
index 38fb8c5..8b81d59 100644
--- a/lib/Net.Messaging.FBM/src/VNLib.Net.Messaging.FBM.csproj
+++ b/lib/Net.Messaging.FBM/src/VNLib.Net.Messaging.FBM.csproj
@@ -46,7 +46,7 @@
<Pack>True</Pack>
<PackagePath>\</PackagePath>
</None>
- <None Include="..\LICENSE.txt">
+ <None Include="..\LICENSE">
<Pack>True</Pack>
<PackagePath>\</PackagePath>
</None>
diff --git a/lib/Plugins/LICENSE.txt b/lib/Net.Rest.Client/LICENSE
index 2848520..5f47f27 100644
--- a/lib/Plugins/LICENSE.txt
+++ b/lib/Net.Rest.Client/LICENSE
@@ -1,3 +1,10 @@
+Copyright (c) 2023 Vaughn Nugent
+
+Contact information
+ Name: Vaughn Nugent
+ Email: vnpublic[at]proton.me
+ Website: https://www.vaughnnugent.com
+
The software in this repository is licensed under the GNU GPL version 2.0 (or any later version).
SPDX-License-Identifier: GPL-2.0-or-later
diff --git a/lib/Net.Rest.Client/build.readme.md b/lib/Net.Rest.Client/build.readme.txt
index e69de29..e69de29 100644
--- a/lib/Net.Rest.Client/build.readme.md
+++ b/lib/Net.Rest.Client/build.readme.txt
diff --git a/lib/Net.Rest.Client/src/VNLib.Net.Rest.Client.csproj b/lib/Net.Rest.Client/src/VNLib.Net.Rest.Client.csproj
index fb626db..b0b68ed 100644
--- a/lib/Net.Rest.Client/src/VNLib.Net.Rest.Client.csproj
+++ b/lib/Net.Rest.Client/src/VNLib.Net.Rest.Client.csproj
@@ -50,15 +50,11 @@
</ItemGroup>
<ItemGroup>
- <Folder Include="Exceptions\" />
- </ItemGroup>
-
- <ItemGroup>
<None Include="..\README.md">
<Pack>True</Pack>
<PackagePath>\</PackagePath>
</None>
- <None Include="..\LICENSE.txt">
+ <None Include="..\LICENSE">
<Pack>True</Pack>
<PackagePath>\</PackagePath>
</None>
diff --git a/lib/Net.Messaging.FBM/LICENSE.txt b/lib/Net.Transport.SimpleTCP/LICENSE
index 147bcd6..982df24 100644
--- a/lib/Net.Messaging.FBM/LICENSE.txt
+++ b/lib/Net.Transport.SimpleTCP/LICENSE
@@ -1,8 +1,8 @@
-Copyright (c) 2022 Vaughn Nugent
+Copyright (c) 2023 Vaughn Nugent
Contact information
Name: Vaughn Nugent
- Email: public[at]vaughnnugent[dot]com
+ Email: vnpublic[at]proton.me
Website: https://www.vaughnnugent.com
The software in this repository is licensed under the GNU Affero GPL version 3.0 (or any later version).
diff --git a/lib/Net.Transport.SimpleTCP/build.readme.md b/lib/Net.Transport.SimpleTCP/build.readme.txt
index e69de29..e69de29 100644
--- a/lib/Net.Transport.SimpleTCP/build.readme.md
+++ b/lib/Net.Transport.SimpleTCP/build.readme.txt
diff --git a/lib/Net.Transport.SimpleTCP/src/VNLib.Net.Transport.SimpleTCP.csproj b/lib/Net.Transport.SimpleTCP/src/VNLib.Net.Transport.SimpleTCP.csproj
index 8c9ef84..4003666 100644
--- a/lib/Net.Transport.SimpleTCP/src/VNLib.Net.Transport.SimpleTCP.csproj
+++ b/lib/Net.Transport.SimpleTCP/src/VNLib.Net.Transport.SimpleTCP.csproj
@@ -44,7 +44,7 @@
<Pack>True</Pack>
<PackagePath>\</PackagePath>
</None>
- <None Include="..\LICENSE.txt">
+ <None Include="..\LICENSE">
<Pack>True</Pack>
<PackagePath>\</PackagePath>
</None>
diff --git a/lib/Net.Transport.SimpleTCP/LICENSE.txt b/lib/Plugins.Essentials.ServiceStack/LICENSE
index 147bcd6..982df24 100644
--- a/lib/Net.Transport.SimpleTCP/LICENSE.txt
+++ b/lib/Plugins.Essentials.ServiceStack/LICENSE
@@ -1,8 +1,8 @@
-Copyright (c) 2022 Vaughn Nugent
+Copyright (c) 2023 Vaughn Nugent
Contact information
Name: Vaughn Nugent
- Email: public[at]vaughnnugent[dot]com
+ Email: vnpublic[at]proton.me
Website: https://www.vaughnnugent.com
The software in this repository is licensed under the GNU Affero GPL version 3.0 (or any later version).
diff --git a/lib/Plugins.Essentials.ServiceStack/README.md b/lib/Plugins.Essentials.ServiceStack/README.md
index aa33435..240b5fc 100644
--- a/lib/Plugins.Essentials.ServiceStack/README.md
+++ b/lib/Plugins.Essentials.ServiceStack/README.md
@@ -1,68 +1,15 @@
# VNLib.Plugins.Essentials.ServiceStack
-This library contains all of the utilities required for an application to build VNLib.Net.Http.HttpServer listeners for nearly unlimited virtual hosts.
+*A toolkit library for building full http stacks with the Plugins.Essentials framework into your application with hardware being the only limitation*
-#### Builds
-Debug build w/ symbols & xml docs, release builds, NuGet packages, and individually packaged source code are available on my [website](https://www.vaughnnugent.com/resources/software). All tar-gzip (.tgz) files will have an associated .sha384 appended checksum of the desired download file.
+## Builds
+Debug build w/ symbols & xml docs, release builds, NuGet packages, and individually packaged source code are available on my website (link below). All tar-gzip (.tgz) files will have an associated .sha384 appended checksum of the desired download file.
-### Breakdown
-
-**HttpServiceStack** - This immutable data structure represents a collection of listening HttpServer instances across the ServiceDomain, and manages the entire lifecycle of those servers.
-
-**ServiceDomain** - The immutable collection of ServiceGroups and their dynamically loaded plugins that represent the bindings between the listening servers and their application code. The service domain handles plugin reload events and their dynamic endpoint updates.
-
-**ServiceGroup** - The immutable collection of service hosts that will share a common HttpServer because they have the same endpoint and TLS/SSL status (enabled or not)
-
-**IServiceHost** - Represents an immutable container exposing the EventProcessor used to execute host specific operations and the transport information (IHostTransportInfo)
-
-**IHostTransportInfo** - The service transport information (desired network endpoint to listen on, and an optional X509Certificate)
-
-**HttpServiceStackBuilder** - The builder class used to build the HttpServiceStack
-
-## Usage
-Again, this library may be used broadly and therefor I will only show basic usage to generate listeners for applications.
-
-```programming language C#
-public static int main (string[] args)
-{
- //Start with the new builder
- HttpServiceStackBuilder builder = new();
-
- //Build the service domain by loading all IServiceHosts
- bool built = builder.ServiceDomain.BuildDomain( hostCollection => ... );
-
- //Check status
- if(!built)
- {
- return -1;
- }
-
- //Load dynamic plugins
- Task loading = builder.ServiceDomain.LoadPlugins(<hostConfig>,<IlogProvider>);
- //wait for loading, we don't need to but if plugins don't load we may choose to exit
- loading.Wait();
-
- //Builds servers by retrieving required ITransportProvider for each service group
- builder.BuildServers(<HttpConfig>, group => ... );
-
- //Get service stack, in a using statement to cleanup.
- using HttpServiceStack serviceStack = builder.ServiceStack;
-
- //Start servers
- serviceStack.StartServers();
-
- ... Wait for process exit
-
- //Stop servers and exit process
- serviceStack.StopAndWaitAsync().Wait();
-
- return 0;
-}
-```
-
-## License
-
-The software in this repository is licensed under the GNU Affero General Public License (or any later version).
-See the LICENSE files for more information.
+## Docs and Guides
+Documentation, specifications, and setup guides are available on my website.
+[Docs and Articles](https://www.vaughnnugent.com/resources/software/articles?tags=docs,_VNLib.Plugins.Essentials.ServiceStack)
+[Builds and Source](https://www.vaughnnugent.com/resources/software/modules/VNLib.Core)
+## License
+The software in this repository is licensed under the GNU Affero General Public License (or any later version). See the LICENSE files for more information. \ No newline at end of file
diff --git a/lib/Plugins.Essentials.ServiceStack/build.readme.md b/lib/Plugins.Essentials.ServiceStack/build.readme.txt
index e69de29..e69de29 100644
--- a/lib/Plugins.Essentials.ServiceStack/build.readme.md
+++ b/lib/Plugins.Essentials.ServiceStack/build.readme.txt
diff --git a/lib/Plugins.Essentials.ServiceStack/src/HttpServiceStackBuilder.cs b/lib/Plugins.Essentials.ServiceStack/src/Construction/HttpServiceStackBuilder.cs
index d85d164..763eb26 100644
--- a/lib/Plugins.Essentials.ServiceStack/src/HttpServiceStackBuilder.cs
+++ b/lib/Plugins.Essentials.ServiceStack/src/Construction/HttpServiceStackBuilder.cs
@@ -30,7 +30,7 @@ using VNLib.Net.Http;
using VNLib.Plugins.Runtime;
-namespace VNLib.Plugins.Essentials.ServiceStack
+namespace VNLib.Plugins.Essentials.ServiceStack.Construction
{
/// <summary>
/// A data structure used to build/create a <see cref="HttpServiceStack"/>
@@ -93,7 +93,7 @@ namespace VNLib.Plugins.Essentials.ServiceStack
/// <returns>The current instance for chaining</returns>
public HttpServiceStackBuilder WithBuiltInHttp(Func<ServiceGroup, ITransportProvider> transport, HttpConfig config)
{
- return WithHttp(sg => new HttpServer(config, transport(sg), sg.Hosts.Select(static p => p.Processor)));
+ return WithHttp(sg => new HttpServer(config, transport(sg), sg.Hosts.Select(static p => p.Processor)));
}
/// <summary>
@@ -156,8 +156,8 @@ namespace VNLib.Plugins.Essentials.ServiceStack
public void BuildStack()
{ }
-
- public void Dispose()
+
+ public void Dispose()
{ }
}
}
diff --git a/lib/Plugins.Essentials.ServiceStack/src/IAccountSecUpdateable.cs b/lib/Plugins.Essentials.ServiceStack/src/Construction/IAccountSecUpdateable.cs
index 43c55ce..eee7a2e 100644
--- a/lib/Plugins.Essentials.ServiceStack/src/IAccountSecUpdateable.cs
+++ b/lib/Plugins.Essentials.ServiceStack/src/Construction/IAccountSecUpdateable.cs
@@ -25,7 +25,7 @@
using VNLib.Plugins.Essentials.Accounts;
-namespace VNLib.Plugins.Essentials.ServiceStack
+namespace VNLib.Plugins.Essentials.ServiceStack.Construction
{
/// <summary>
/// Adds functionality to event processors to allow them to be updated
diff --git a/lib/Plugins.Essentials.ServiceStack/src/IDomainBuilder.cs b/lib/Plugins.Essentials.ServiceStack/src/Construction/IDomainBuilder.cs
index dc6dac5..19d2a96 100644
--- a/lib/Plugins.Essentials.ServiceStack/src/IDomainBuilder.cs
+++ b/lib/Plugins.Essentials.ServiceStack/src/Construction/IDomainBuilder.cs
@@ -26,7 +26,7 @@ using System.IO;
using VNLib.Utils.Logging;
-namespace VNLib.Plugins.Essentials.ServiceStack
+namespace VNLib.Plugins.Essentials.ServiceStack.Construction
{
/// <summary>
/// Allows for defining virtual hosts for the service stack
diff --git a/lib/Plugins.Essentials.ServiceStack/src/IVirtualHostBuilder.cs b/lib/Plugins.Essentials.ServiceStack/src/Construction/IVirtualHostBuilder.cs
index 8db3103..b2f3b1b 100644
--- a/lib/Plugins.Essentials.ServiceStack/src/IVirtualHostBuilder.cs
+++ b/lib/Plugins.Essentials.ServiceStack/src/Construction/IVirtualHostBuilder.cs
@@ -25,7 +25,7 @@
using System;
-namespace VNLib.Plugins.Essentials.ServiceStack
+namespace VNLib.Plugins.Essentials.ServiceStack.Construction
{
/// <summary>
/// Allows for configuring a single virtual host
diff --git a/lib/Plugins.Essentials.ServiceStack/src/IVirtualHostHooks.cs b/lib/Plugins.Essentials.ServiceStack/src/Construction/IVirtualHostHooks.cs
index e2d5382..6691d6b 100644
--- a/lib/Plugins.Essentials.ServiceStack/src/IVirtualHostHooks.cs
+++ b/lib/Plugins.Essentials.ServiceStack/src/Construction/IVirtualHostHooks.cs
@@ -27,7 +27,7 @@ using System.Threading.Tasks;
using VNLib.Net.Http;
-namespace VNLib.Plugins.Essentials.ServiceStack
+namespace VNLib.Plugins.Essentials.ServiceStack.Construction
{
/// <summary>
/// Represents a type that will handle http events for a virtual host
diff --git a/lib/Plugins.Essentials.ServiceStack/src/SsBuilderExtensions.cs b/lib/Plugins.Essentials.ServiceStack/src/Construction/SsBuilderExtensions.cs
index b6c21fb..d518218 100644
--- a/lib/Plugins.Essentials.ServiceStack/src/SsBuilderExtensions.cs
+++ b/lib/Plugins.Essentials.ServiceStack/src/Construction/SsBuilderExtensions.cs
@@ -37,8 +37,7 @@ using VNLib.Plugins.Essentials.Content;
using VNLib.Plugins.Essentials.Sessions;
using VNLib.Plugins.Essentials.Middleware;
-
-namespace VNLib.Plugins.Essentials.ServiceStack
+namespace VNLib.Plugins.Essentials.ServiceStack.Construction
{
/// <summary>
@@ -53,7 +52,7 @@ namespace VNLib.Plugins.Essentials.ServiceStack
/// </summary>
/// <param name="stack"></param>
/// <returns>The <see cref="IDomainBuilder"/> used to define your service domain</returns>
- public static IDomainBuilder WithDomain(this HttpServiceStackBuilder stack) => WithDomain(stack, p => new BasicVirtualHost(p.Clone()));
+ public static IDomainBuilder WithDomain(this HttpServiceStackBuilder stack) => stack.WithDomain(p => new BasicVirtualHost(p.Clone()));
/// <summary>
/// Creates a new <see cref="IDomainBuilder"/> instance to define your
@@ -79,7 +78,7 @@ namespace VNLib.Plugins.Essentials.ServiceStack
public static IDomainBuilder WithDomain<T>(this HttpServiceStackBuilder stack, Func<VirtualHostConfiguration, T> callback) where T : EventProcessor, IAccountSecUpdateable
{
List<VirtualHostConfiguration> configs = new();
- DomainBuilder domains = new (configs, stack);
+ DomainBuilder domains = new(configs, stack);
//Add callback to capture this collection of configs when built
stack.AddHosts(() => configs.Select(c => new CustomServiceHost<T>(c.Clone(), callback(c))).ToArray());
@@ -99,6 +98,19 @@ namespace VNLib.Plugins.Essentials.ServiceStack
return vhBuilder;
}
+ /// <summary>
+ /// Adds multiple <see cref="IHttpMiddleware"/> instances to the virtual host
+ /// </summary>
+ /// <param name="vhBuilder"></param>
+ /// <param name="middleware">The array of middleware instances to add to the collection</param>
+ /// <returns></returns>
+ public static IVirtualHostBuilder WithMiddleware(this IVirtualHostBuilder vhBuilder, params IHttpMiddleware[] middleware)
+ {
+ vhBuilder.WithOption(c => Array.ForEach(middleware, m => c.CustomMiddleware.Add(m)));
+ return vhBuilder;
+ }
+
+
public static IVirtualHostBuilder WithLogger(this IVirtualHostBuilder vhBuilder, ILogProvider logger)
{
vhBuilder.WithOption(c => c.LogProvider = logger);
@@ -169,6 +181,7 @@ namespace VNLib.Plugins.Essentials.ServiceStack
return vhBuilder;
}
+
private static void AddHosts(this HttpServiceStackBuilder stack, Func<IServiceHost[]> hosts) => stack.WithDomain(p => Array.ForEach(hosts(), h => p.Add(h)));
private static void OnPluginServiceEvent<T>(this IManagedPlugin plugin, Action<T> loader)
@@ -226,7 +239,7 @@ namespace VNLib.Plugins.Essentials.ServiceStack
this.Instance = Instance;
//Add middleware to the chain
- foreach(IHttpMiddleware mw in Config.CustomMiddleware)
+ foreach (IHttpMiddleware mw in Config.CustomMiddleware)
{
Instance.MiddlewareChain.AddLast(mw);
}
@@ -268,7 +281,7 @@ namespace VNLib.Plugins.Essentials.ServiceStack
plugin.OnPluginServiceEvent<IHttpMiddleware[]>(p => Array.ForEach(p, mw => Instance.MiddlewareChain.RemoveMiddleware(mw)));
}
}
-
+
private sealed class BasicVirtualHost : EventProcessor, IAccountSecUpdateable
{
diff --git a/lib/Plugins.Essentials.ServiceStack/src/VirtualHostConfiguration.cs b/lib/Plugins.Essentials.ServiceStack/src/Construction/VirtualHostConfiguration.cs
index 4734a5a..97ad905 100644
--- a/lib/Plugins.Essentials.ServiceStack/src/VirtualHostConfiguration.cs
+++ b/lib/Plugins.Essentials.ServiceStack/src/Construction/VirtualHostConfiguration.cs
@@ -31,7 +31,7 @@ using System.Security.Cryptography.X509Certificates;
using VNLib.Utils.Logging;
using VNLib.Plugins.Essentials.Middleware;
-namespace VNLib.Plugins.Essentials.ServiceStack
+namespace VNLib.Plugins.Essentials.ServiceStack.Construction
{
/// <summary>
/// A virtual host configuration container
@@ -82,7 +82,7 @@ namespace VNLib.Plugins.Essentials.ServiceStack
/// File attributes that must be matched for the file to be accessed, defaults to all allowed
/// <para> Default: 0xFFFFFFFF</para>
/// </summary>
- public FileAttributes AllowedAttributes { get; set; } = unchecked((FileAttributes)(0xFFFFFFFF));
+ public FileAttributes AllowedAttributes { get; set; } = unchecked((FileAttributes)0xFFFFFFFF);
/// <summary>
/// Files that match any attribute flag set will be denied
@@ -94,7 +94,7 @@ namespace VNLib.Plugins.Essentials.ServiceStack
/// A table of known downstream servers/ports that can be trusted to proxy connections
/// <para>Default: empty set</para>
/// </summary>
- public IReadOnlySet<IPAddress> DownStreamServers { get; set; } = new HashSet<IPAddress>();
+ public IReadOnlySet<IPAddress> DownStreamServers { get; set; } = new HashSet<IPAddress>();
/// <summary>
/// A <see cref="TimeSpan"/> for how long a connection may remain open before all operations are cancelled
diff --git a/lib/Plugins.Essentials.ServiceStack/src/IPluginController.cs b/lib/Plugins.Essentials.ServiceStack/src/IHttpPluginManager.cs
index 6cece1f..6cece1f 100644
--- a/lib/Plugins.Essentials.ServiceStack/src/IPluginController.cs
+++ b/lib/Plugins.Essentials.ServiceStack/src/IHttpPluginManager.cs
diff --git a/lib/Plugins.Essentials.ServiceStack/src/VNLib.Plugins.Essentials.ServiceStack.csproj b/lib/Plugins.Essentials.ServiceStack/src/VNLib.Plugins.Essentials.ServiceStack.csproj
index b3ba43a..afc4774 100644
--- a/lib/Plugins.Essentials.ServiceStack/src/VNLib.Plugins.Essentials.ServiceStack.csproj
+++ b/lib/Plugins.Essentials.ServiceStack/src/VNLib.Plugins.Essentials.ServiceStack.csproj
@@ -37,7 +37,7 @@
<Pack>True</Pack>
<PackagePath>\</PackagePath>
</None>
- <None Include="..\LICENSE.txt">
+ <None Include="..\LICENSE">
<Pack>True</Pack>
<PackagePath>\</PackagePath>
</None>
diff --git a/lib/Plugins.Essentials/LICENSE b/lib/Plugins.Essentials/LICENSE
new file mode 100644
index 0000000..982df24
--- /dev/null
+++ b/lib/Plugins.Essentials/LICENSE
@@ -0,0 +1,195 @@
+Copyright (c) 2023 Vaughn Nugent
+
+Contact information
+ Name: Vaughn Nugent
+ Email: vnpublic[at]proton.me
+ Website: https://www.vaughnnugent.com
+
+The software in this repository is licensed under the GNU Affero GPL version 3.0 (or any later version).
+
+GNU AFFERO GENERAL PUBLIC LICENSE
+
+Version 3, 19 November 2007
+
+Copyright © 2007 Free Software Foundation, Inc. <https://fsf.org/>
+Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed.
+Preamble
+
+The GNU Affero General Public License is a free, copyleft license for software and other kinds of works, specifically designed to ensure cooperation with the community in the case of network server software.
+
+The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, our General Public Licenses are intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users.
+
+When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for them if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things.
+
+Developers that use our General Public Licenses protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License which gives you legal permission to copy, distribute and/or modify the software.
+
+A secondary benefit of defending all users' freedom is that improvements made in alternate versions of the program, if they receive widespread use, become available for other developers to incorporate. Many developers of free software are heartened and encouraged by the resulting cooperation. However, in the case of software used on network servers, this result may fail to come about. The GNU General Public License permits making a modified version and letting the public access it on a server without ever releasing its source code to the public.
+
+The GNU Affero General Public License is designed specifically to ensure that, in such cases, the modified source code becomes available to the community. It requires the operator of a network server to provide the source code of the modified version running there to the users of that server. Therefore, public use of a modified version, on a publicly accessible server, gives the public access to the source code of the modified version.
+
+An older license, called the Affero General Public License and published by Affero, was designed to accomplish similar goals. This is a different license, not a version of the Affero GPL, but Affero has released a new version of the Affero GPL which permits relicensing under this license.
+
+The precise terms and conditions for copying, distribution and modification follow.
+TERMS AND CONDITIONS
+0. Definitions.
+
+"This License" refers to version 3 of the GNU Affero General Public License.
+
+"Copyright" also means copyright-like laws that apply to other kinds of works, such as semiconductor masks.
+
+"The Program" refers to any copyrightable work licensed under this License. Each licensee is addressed as "you". "Licensees" and "recipients" may be individuals or organizations.
+
+To "modify" a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a "modified version" of the earlier work or a work "based on" the earlier work.
+
+A "covered work" means either the unmodified Program or a work based on the Program.
+
+To "propagate" a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well.
+
+To "convey" a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying.
+
+An interactive user interface displays "Appropriate Legal Notices" to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion.
+1. Source Code.
+
+The "source code" for a work means the preferred form of the work for making modifications to it. "Object code" means any non-source form of a work.
+
+A "Standard Interface" means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language.
+
+The "System Libraries" of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A "Major Component", in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it.
+
+The "Corresponding Source" for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work.
+
+The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source.
+
+The Corresponding Source for a work in source code form is that same work.
+2. Basic Permissions.
+
+All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law.
+
+You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you.
+
+Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary.
+3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures.
+
+When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures.
+4. Conveying Verbatim Copies.
+
+You may convey verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program.
+
+You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee.
+5. Conveying Modified Source Versions.
+
+You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions:
+
+ a) The work must carry prominent notices stating that you modified it, and giving a relevant date.
+ b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to "keep intact all notices".
+ c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it.
+ d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so.
+
+A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an "aggregate" if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate.
+6. Conveying Non-Source Forms.
+
+You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways:
+
+ a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange.
+ b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge.
+ c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b.
+ d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements.
+ e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d.
+
+A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work.
+
+A "User Product" is either (1) a "consumer product", which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, "normally used" refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product.
+
+"Installation Information" for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made.
+
+If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM).
+
+The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network.
+
+Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying.
+7. Additional Terms.
+
+"Additional permissions" are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions.
+
+When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission.
+
+Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms:
+
+ a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or
+ b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or
+ c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or
+ d) Limiting the use for publicity purposes of names of licensors or authors of the material; or
+ e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or
+ f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors.
+
+All other non-permissive additional terms are considered "further restrictions" within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying.
+
+If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms.
+
+Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way.
+8. Termination.
+
+You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11).
+
+However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation.
+
+Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice.
+
+Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10.
+9. Acceptance Not Required for Having Copies.
+
+You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so.
+10. Automatic Licensing of Downstream Recipients.
+
+Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License.
+
+An "entity transaction" is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts.
+
+You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it.
+11. Patents.
+
+A "contributor" is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's "contributor version".
+
+A contributor's "essential patent claims" are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, "control" includes the right to grant patent sublicenses in a manner consistent with the requirements of this License.
+
+Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version.
+
+In the following three paragraphs, a "patent license" is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To "grant" such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party.
+
+If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. "Knowingly relying" means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid.
+
+If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it.
+
+A patent license is "discriminatory" if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007.
+
+Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law.
+12. No Surrender of Others' Freedom.
+
+If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program.
+13. Remote Network Interaction; Use with the GNU General Public License.
+
+Notwithstanding any other provision of this License, if you modify the Program, your modified version must prominently offer all users interacting with it remotely through a computer network (if your version supports such interaction) an opportunity to receive the Corresponding Source of your version by providing access to the Corresponding Source from a network server at no charge, through some standard or customary means of facilitating copying of software. This Corresponding Source shall include the Corresponding Source for any work covered by version 3 of the GNU General Public License that is incorporated pursuant to the following paragraph.
+
+Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the work with which it is combined will remain governed by version 3 of the GNU General Public License.
+14. Revised Versions of this License.
+
+The Free Software Foundation may publish revised and/or new versions of the GNU Affero General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program specifies that a certain numbered version of the GNU Affero General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU Affero General Public License, you may choose any version ever published by the Free Software Foundation.
+
+If the Program specifies that a proxy can decide which future versions of the GNU Affero General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program.
+
+Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version.
+15. Disclaimer of Warranty.
+
+THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+16. Limitation of Liability.
+
+IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+17. Interpretation of Sections 15 and 16.
+
+If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee.
+
+END OF TERMS AND CONDITIONS \ No newline at end of file
diff --git a/lib/Plugins.Essentials/LICENSE.txt b/lib/Plugins.Essentials/LICENSE.txt
deleted file mode 100644
index 147bcd6..0000000
--- a/lib/Plugins.Essentials/LICENSE.txt
+++ /dev/null
@@ -1,195 +0,0 @@
-Copyright (c) 2022 Vaughn Nugent
-
-Contact information
- Name: Vaughn Nugent
- Email: public[at]vaughnnugent[dot]com
- Website: https://www.vaughnnugent.com
-
-The software in this repository is licensed under the GNU Affero GPL version 3.0 (or any later version).
-
-GNU AFFERO GENERAL PUBLIC LICENSE
-
-Version 3, 19 November 2007
-
-Copyright © 2007 Free Software Foundation, Inc. <https://fsf.org/>
-Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed.
-Preamble
-
-The GNU Affero General Public License is a free, copyleft license for software and other kinds of works, specifically designed to ensure cooperation with the community in the case of network server software.
-
-The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, our General Public Licenses are intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users.
-
-When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for them if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things.
-
-Developers that use our General Public Licenses protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License which gives you legal permission to copy, distribute and/or modify the software.
-
-A secondary benefit of defending all users' freedom is that improvements made in alternate versions of the program, if they receive widespread use, become available for other developers to incorporate. Many developers of free software are heartened and encouraged by the resulting cooperation. However, in the case of software used on network servers, this result may fail to come about. The GNU General Public License permits making a modified version and letting the public access it on a server without ever releasing its source code to the public.
-
-The GNU Affero General Public License is designed specifically to ensure that, in such cases, the modified source code becomes available to the community. It requires the operator of a network server to provide the source code of the modified version running there to the users of that server. Therefore, public use of a modified version, on a publicly accessible server, gives the public access to the source code of the modified version.
-
-An older license, called the Affero General Public License and published by Affero, was designed to accomplish similar goals. This is a different license, not a version of the Affero GPL, but Affero has released a new version of the Affero GPL which permits relicensing under this license.
-
-The precise terms and conditions for copying, distribution and modification follow.
-TERMS AND CONDITIONS
-0. Definitions.
-
-"This License" refers to version 3 of the GNU Affero General Public License.
-
-"Copyright" also means copyright-like laws that apply to other kinds of works, such as semiconductor masks.
-
-"The Program" refers to any copyrightable work licensed under this License. Each licensee is addressed as "you". "Licensees" and "recipients" may be individuals or organizations.
-
-To "modify" a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a "modified version" of the earlier work or a work "based on" the earlier work.
-
-A "covered work" means either the unmodified Program or a work based on the Program.
-
-To "propagate" a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well.
-
-To "convey" a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying.
-
-An interactive user interface displays "Appropriate Legal Notices" to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion.
-1. Source Code.
-
-The "source code" for a work means the preferred form of the work for making modifications to it. "Object code" means any non-source form of a work.
-
-A "Standard Interface" means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language.
-
-The "System Libraries" of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A "Major Component", in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it.
-
-The "Corresponding Source" for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work.
-
-The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source.
-
-The Corresponding Source for a work in source code form is that same work.
-2. Basic Permissions.
-
-All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law.
-
-You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you.
-
-Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary.
-3. Protecting Users' Legal Rights From Anti-Circumvention Law.
-
-No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures.
-
-When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures.
-4. Conveying Verbatim Copies.
-
-You may convey verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program.
-
-You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee.
-5. Conveying Modified Source Versions.
-
-You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions:
-
- a) The work must carry prominent notices stating that you modified it, and giving a relevant date.
- b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to "keep intact all notices".
- c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it.
- d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so.
-
-A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an "aggregate" if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate.
-6. Conveying Non-Source Forms.
-
-You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways:
-
- a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange.
- b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge.
- c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b.
- d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements.
- e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d.
-
-A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work.
-
-A "User Product" is either (1) a "consumer product", which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, "normally used" refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product.
-
-"Installation Information" for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made.
-
-If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM).
-
-The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network.
-
-Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying.
-7. Additional Terms.
-
-"Additional permissions" are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions.
-
-When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission.
-
-Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms:
-
- a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or
- b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or
- c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or
- d) Limiting the use for publicity purposes of names of licensors or authors of the material; or
- e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or
- f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors.
-
-All other non-permissive additional terms are considered "further restrictions" within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying.
-
-If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms.
-
-Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way.
-8. Termination.
-
-You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11).
-
-However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation.
-
-Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice.
-
-Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10.
-9. Acceptance Not Required for Having Copies.
-
-You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so.
-10. Automatic Licensing of Downstream Recipients.
-
-Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License.
-
-An "entity transaction" is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts.
-
-You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it.
-11. Patents.
-
-A "contributor" is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's "contributor version".
-
-A contributor's "essential patent claims" are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, "control" includes the right to grant patent sublicenses in a manner consistent with the requirements of this License.
-
-Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version.
-
-In the following three paragraphs, a "patent license" is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To "grant" such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party.
-
-If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. "Knowingly relying" means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid.
-
-If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it.
-
-A patent license is "discriminatory" if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007.
-
-Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law.
-12. No Surrender of Others' Freedom.
-
-If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program.
-13. Remote Network Interaction; Use with the GNU General Public License.
-
-Notwithstanding any other provision of this License, if you modify the Program, your modified version must prominently offer all users interacting with it remotely through a computer network (if your version supports such interaction) an opportunity to receive the Corresponding Source of your version by providing access to the Corresponding Source from a network server at no charge, through some standard or customary means of facilitating copying of software. This Corresponding Source shall include the Corresponding Source for any work covered by version 3 of the GNU General Public License that is incorporated pursuant to the following paragraph.
-
-Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the work with which it is combined will remain governed by version 3 of the GNU General Public License.
-14. Revised Versions of this License.
-
-The Free Software Foundation may publish revised and/or new versions of the GNU Affero General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns.
-
-Each version is given a distinguishing version number. If the Program specifies that a certain numbered version of the GNU Affero General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU Affero General Public License, you may choose any version ever published by the Free Software Foundation.
-
-If the Program specifies that a proxy can decide which future versions of the GNU Affero General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program.
-
-Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version.
-15. Disclaimer of Warranty.
-
-THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
-16. Limitation of Liability.
-
-IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
-17. Interpretation of Sections 15 and 16.
-
-If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee.
-
-END OF TERMS AND CONDITIONS \ No newline at end of file
diff --git a/lib/Plugins.Essentials/build.readme.md b/lib/Plugins.Essentials/build.readme.txt
index e69de29..e69de29 100644
--- a/lib/Plugins.Essentials/build.readme.md
+++ b/lib/Plugins.Essentials/build.readme.txt
diff --git a/lib/Plugins.Essentials/src/VNLib.Plugins.Essentials.csproj b/lib/Plugins.Essentials/src/VNLib.Plugins.Essentials.csproj
index 6a42c92..805f151 100644
--- a/lib/Plugins.Essentials/src/VNLib.Plugins.Essentials.csproj
+++ b/lib/Plugins.Essentials/src/VNLib.Plugins.Essentials.csproj
@@ -48,7 +48,7 @@
<Pack>True</Pack>
<PackagePath>\</PackagePath>
</None>
- <None Include="..\LICENSE.txt">
+ <None Include="..\LICENSE">
<Pack>True</Pack>
<PackagePath>\</PackagePath>
</None>
diff --git a/lib/Plugins.PluginBase/LICENSE b/lib/Plugins.PluginBase/LICENSE
new file mode 100644
index 0000000..982df24
--- /dev/null
+++ b/lib/Plugins.PluginBase/LICENSE
@@ -0,0 +1,195 @@
+Copyright (c) 2023 Vaughn Nugent
+
+Contact information
+ Name: Vaughn Nugent
+ Email: vnpublic[at]proton.me
+ Website: https://www.vaughnnugent.com
+
+The software in this repository is licensed under the GNU Affero GPL version 3.0 (or any later version).
+
+GNU AFFERO GENERAL PUBLIC LICENSE
+
+Version 3, 19 November 2007
+
+Copyright © 2007 Free Software Foundation, Inc. <https://fsf.org/>
+Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed.
+Preamble
+
+The GNU Affero General Public License is a free, copyleft license for software and other kinds of works, specifically designed to ensure cooperation with the community in the case of network server software.
+
+The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, our General Public Licenses are intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users.
+
+When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for them if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things.
+
+Developers that use our General Public Licenses protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License which gives you legal permission to copy, distribute and/or modify the software.
+
+A secondary benefit of defending all users' freedom is that improvements made in alternate versions of the program, if they receive widespread use, become available for other developers to incorporate. Many developers of free software are heartened and encouraged by the resulting cooperation. However, in the case of software used on network servers, this result may fail to come about. The GNU General Public License permits making a modified version and letting the public access it on a server without ever releasing its source code to the public.
+
+The GNU Affero General Public License is designed specifically to ensure that, in such cases, the modified source code becomes available to the community. It requires the operator of a network server to provide the source code of the modified version running there to the users of that server. Therefore, public use of a modified version, on a publicly accessible server, gives the public access to the source code of the modified version.
+
+An older license, called the Affero General Public License and published by Affero, was designed to accomplish similar goals. This is a different license, not a version of the Affero GPL, but Affero has released a new version of the Affero GPL which permits relicensing under this license.
+
+The precise terms and conditions for copying, distribution and modification follow.
+TERMS AND CONDITIONS
+0. Definitions.
+
+"This License" refers to version 3 of the GNU Affero General Public License.
+
+"Copyright" also means copyright-like laws that apply to other kinds of works, such as semiconductor masks.
+
+"The Program" refers to any copyrightable work licensed under this License. Each licensee is addressed as "you". "Licensees" and "recipients" may be individuals or organizations.
+
+To "modify" a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a "modified version" of the earlier work or a work "based on" the earlier work.
+
+A "covered work" means either the unmodified Program or a work based on the Program.
+
+To "propagate" a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well.
+
+To "convey" a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying.
+
+An interactive user interface displays "Appropriate Legal Notices" to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion.
+1. Source Code.
+
+The "source code" for a work means the preferred form of the work for making modifications to it. "Object code" means any non-source form of a work.
+
+A "Standard Interface" means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language.
+
+The "System Libraries" of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A "Major Component", in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it.
+
+The "Corresponding Source" for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work.
+
+The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source.
+
+The Corresponding Source for a work in source code form is that same work.
+2. Basic Permissions.
+
+All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law.
+
+You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you.
+
+Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary.
+3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures.
+
+When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures.
+4. Conveying Verbatim Copies.
+
+You may convey verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program.
+
+You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee.
+5. Conveying Modified Source Versions.
+
+You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions:
+
+ a) The work must carry prominent notices stating that you modified it, and giving a relevant date.
+ b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to "keep intact all notices".
+ c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it.
+ d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so.
+
+A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an "aggregate" if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate.
+6. Conveying Non-Source Forms.
+
+You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways:
+
+ a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange.
+ b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge.
+ c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b.
+ d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements.
+ e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d.
+
+A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work.
+
+A "User Product" is either (1) a "consumer product", which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, "normally used" refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product.
+
+"Installation Information" for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made.
+
+If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM).
+
+The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network.
+
+Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying.
+7. Additional Terms.
+
+"Additional permissions" are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions.
+
+When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission.
+
+Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms:
+
+ a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or
+ b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or
+ c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or
+ d) Limiting the use for publicity purposes of names of licensors or authors of the material; or
+ e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or
+ f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors.
+
+All other non-permissive additional terms are considered "further restrictions" within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying.
+
+If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms.
+
+Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way.
+8. Termination.
+
+You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11).
+
+However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation.
+
+Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice.
+
+Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10.
+9. Acceptance Not Required for Having Copies.
+
+You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so.
+10. Automatic Licensing of Downstream Recipients.
+
+Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License.
+
+An "entity transaction" is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts.
+
+You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it.
+11. Patents.
+
+A "contributor" is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's "contributor version".
+
+A contributor's "essential patent claims" are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, "control" includes the right to grant patent sublicenses in a manner consistent with the requirements of this License.
+
+Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version.
+
+In the following three paragraphs, a "patent license" is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To "grant" such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party.
+
+If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. "Knowingly relying" means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid.
+
+If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it.
+
+A patent license is "discriminatory" if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007.
+
+Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law.
+12. No Surrender of Others' Freedom.
+
+If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program.
+13. Remote Network Interaction; Use with the GNU General Public License.
+
+Notwithstanding any other provision of this License, if you modify the Program, your modified version must prominently offer all users interacting with it remotely through a computer network (if your version supports such interaction) an opportunity to receive the Corresponding Source of your version by providing access to the Corresponding Source from a network server at no charge, through some standard or customary means of facilitating copying of software. This Corresponding Source shall include the Corresponding Source for any work covered by version 3 of the GNU General Public License that is incorporated pursuant to the following paragraph.
+
+Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the work with which it is combined will remain governed by version 3 of the GNU General Public License.
+14. Revised Versions of this License.
+
+The Free Software Foundation may publish revised and/or new versions of the GNU Affero General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program specifies that a certain numbered version of the GNU Affero General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU Affero General Public License, you may choose any version ever published by the Free Software Foundation.
+
+If the Program specifies that a proxy can decide which future versions of the GNU Affero General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program.
+
+Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version.
+15. Disclaimer of Warranty.
+
+THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+16. Limitation of Liability.
+
+IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+17. Interpretation of Sections 15 and 16.
+
+If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee.
+
+END OF TERMS AND CONDITIONS \ No newline at end of file
diff --git a/lib/Plugins.PluginBase/LICENSE.txt b/lib/Plugins.PluginBase/LICENSE.txt
deleted file mode 100644
index 147bcd6..0000000
--- a/lib/Plugins.PluginBase/LICENSE.txt
+++ /dev/null
@@ -1,195 +0,0 @@
-Copyright (c) 2022 Vaughn Nugent
-
-Contact information
- Name: Vaughn Nugent
- Email: public[at]vaughnnugent[dot]com
- Website: https://www.vaughnnugent.com
-
-The software in this repository is licensed under the GNU Affero GPL version 3.0 (or any later version).
-
-GNU AFFERO GENERAL PUBLIC LICENSE
-
-Version 3, 19 November 2007
-
-Copyright © 2007 Free Software Foundation, Inc. <https://fsf.org/>
-Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed.
-Preamble
-
-The GNU Affero General Public License is a free, copyleft license for software and other kinds of works, specifically designed to ensure cooperation with the community in the case of network server software.
-
-The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, our General Public Licenses are intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users.
-
-When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for them if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things.
-
-Developers that use our General Public Licenses protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License which gives you legal permission to copy, distribute and/or modify the software.
-
-A secondary benefit of defending all users' freedom is that improvements made in alternate versions of the program, if they receive widespread use, become available for other developers to incorporate. Many developers of free software are heartened and encouraged by the resulting cooperation. However, in the case of software used on network servers, this result may fail to come about. The GNU General Public License permits making a modified version and letting the public access it on a server without ever releasing its source code to the public.
-
-The GNU Affero General Public License is designed specifically to ensure that, in such cases, the modified source code becomes available to the community. It requires the operator of a network server to provide the source code of the modified version running there to the users of that server. Therefore, public use of a modified version, on a publicly accessible server, gives the public access to the source code of the modified version.
-
-An older license, called the Affero General Public License and published by Affero, was designed to accomplish similar goals. This is a different license, not a version of the Affero GPL, but Affero has released a new version of the Affero GPL which permits relicensing under this license.
-
-The precise terms and conditions for copying, distribution and modification follow.
-TERMS AND CONDITIONS
-0. Definitions.
-
-"This License" refers to version 3 of the GNU Affero General Public License.
-
-"Copyright" also means copyright-like laws that apply to other kinds of works, such as semiconductor masks.
-
-"The Program" refers to any copyrightable work licensed under this License. Each licensee is addressed as "you". "Licensees" and "recipients" may be individuals or organizations.
-
-To "modify" a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a "modified version" of the earlier work or a work "based on" the earlier work.
-
-A "covered work" means either the unmodified Program or a work based on the Program.
-
-To "propagate" a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well.
-
-To "convey" a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying.
-
-An interactive user interface displays "Appropriate Legal Notices" to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion.
-1. Source Code.
-
-The "source code" for a work means the preferred form of the work for making modifications to it. "Object code" means any non-source form of a work.
-
-A "Standard Interface" means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language.
-
-The "System Libraries" of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A "Major Component", in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it.
-
-The "Corresponding Source" for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work.
-
-The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source.
-
-The Corresponding Source for a work in source code form is that same work.
-2. Basic Permissions.
-
-All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law.
-
-You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you.
-
-Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary.
-3. Protecting Users' Legal Rights From Anti-Circumvention Law.
-
-No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures.
-
-When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures.
-4. Conveying Verbatim Copies.
-
-You may convey verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program.
-
-You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee.
-5. Conveying Modified Source Versions.
-
-You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions:
-
- a) The work must carry prominent notices stating that you modified it, and giving a relevant date.
- b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to "keep intact all notices".
- c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it.
- d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so.
-
-A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an "aggregate" if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate.
-6. Conveying Non-Source Forms.
-
-You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways:
-
- a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange.
- b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge.
- c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b.
- d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements.
- e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d.
-
-A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work.
-
-A "User Product" is either (1) a "consumer product", which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, "normally used" refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product.
-
-"Installation Information" for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made.
-
-If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM).
-
-The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network.
-
-Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying.
-7. Additional Terms.
-
-"Additional permissions" are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions.
-
-When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission.
-
-Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms:
-
- a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or
- b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or
- c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or
- d) Limiting the use for publicity purposes of names of licensors or authors of the material; or
- e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or
- f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors.
-
-All other non-permissive additional terms are considered "further restrictions" within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying.
-
-If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms.
-
-Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way.
-8. Termination.
-
-You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11).
-
-However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation.
-
-Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice.
-
-Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10.
-9. Acceptance Not Required for Having Copies.
-
-You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so.
-10. Automatic Licensing of Downstream Recipients.
-
-Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License.
-
-An "entity transaction" is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts.
-
-You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it.
-11. Patents.
-
-A "contributor" is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's "contributor version".
-
-A contributor's "essential patent claims" are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, "control" includes the right to grant patent sublicenses in a manner consistent with the requirements of this License.
-
-Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version.
-
-In the following three paragraphs, a "patent license" is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To "grant" such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party.
-
-If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. "Knowingly relying" means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid.
-
-If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it.
-
-A patent license is "discriminatory" if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007.
-
-Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law.
-12. No Surrender of Others' Freedom.
-
-If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program.
-13. Remote Network Interaction; Use with the GNU General Public License.
-
-Notwithstanding any other provision of this License, if you modify the Program, your modified version must prominently offer all users interacting with it remotely through a computer network (if your version supports such interaction) an opportunity to receive the Corresponding Source of your version by providing access to the Corresponding Source from a network server at no charge, through some standard or customary means of facilitating copying of software. This Corresponding Source shall include the Corresponding Source for any work covered by version 3 of the GNU General Public License that is incorporated pursuant to the following paragraph.
-
-Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the work with which it is combined will remain governed by version 3 of the GNU General Public License.
-14. Revised Versions of this License.
-
-The Free Software Foundation may publish revised and/or new versions of the GNU Affero General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns.
-
-Each version is given a distinguishing version number. If the Program specifies that a certain numbered version of the GNU Affero General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU Affero General Public License, you may choose any version ever published by the Free Software Foundation.
-
-If the Program specifies that a proxy can decide which future versions of the GNU Affero General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program.
-
-Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version.
-15. Disclaimer of Warranty.
-
-THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
-16. Limitation of Liability.
-
-IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
-17. Interpretation of Sections 15 and 16.
-
-If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee.
-
-END OF TERMS AND CONDITIONS \ No newline at end of file
diff --git a/lib/Plugins.PluginBase/build.readme.md b/lib/Plugins.PluginBase/build.readme
index e69de29..e69de29 100644
--- a/lib/Plugins.PluginBase/build.readme.md
+++ b/lib/Plugins.PluginBase/build.readme
diff --git a/lib/Plugins.PluginBase/src/VNLib.Plugins.PluginBase.csproj b/lib/Plugins.PluginBase/src/VNLib.Plugins.PluginBase.csproj
index cd91185..8655615 100644
--- a/lib/Plugins.PluginBase/src/VNLib.Plugins.PluginBase.csproj
+++ b/lib/Plugins.PluginBase/src/VNLib.Plugins.PluginBase.csproj
@@ -56,7 +56,7 @@
<Pack>True</Pack>
<PackagePath>\</PackagePath>
</None>
- <None Include="..\LICENSE.txt">
+ <None Include="..\LICENSE">
<Pack>True</Pack>
<PackagePath>\</PackagePath>
</None>
diff --git a/lib/NativeHeapApi/LICENSE.txt b/lib/Plugins.Runtime/LICENSE
index 2848520..2848520 100644
--- a/lib/NativeHeapApi/LICENSE.txt
+++ b/lib/Plugins.Runtime/LICENSE
diff --git a/lib/Plugins.Runtime/README.md b/lib/Plugins.Runtime/README.md
index ca36900..18e3829 100644
--- a/lib/Plugins.Runtime/README.md
+++ b/lib/Plugins.Runtime/README.md
@@ -2,77 +2,16 @@
A structured library for implementing runtime-loaded assemblies that expose types that implement the IPlugin runtime type and manages their lifecycle including unload-able (collectible) assemblies. Type instances are fully managed and carefully exposed as to safely control an instance's lifecycle.
-### Builds
-Debug build w/ symbols & xml docs, release builds, NuGet packages, and individually packaged source code are available on my [website](https://www.vaughnnugent.com/resources/software/modules). All tar-gzip (.tgz) files will have an associated .sha384 appended checksum of the desired download file.
+**This library has no external dependencies**
-## Implementation notes
-This library may seem over-complicated for managing runtime plugin loading, but it was designed to remedy the common pitfalls of dynamic type loading while also providing implementation freedom to the library consumer/developer. Dependency hell is a difficult issue to work around and I have found it is really up to the application use case to know how, when, and where to load dependencies that will avoid type mismatches but allow for the best interoperability. So that being said, it is your responsibility to implement the `IPluginAssemblyLoader` interface that loads the desired plugin assembly when required and may optionally implement type unloading (likely through a collectable `AssemblyLoadContext`).
+## Builds
+Debug build w/ symbols & xml docs, release builds, NuGet packages, and individually packaged source code are available on my website (link below). All tar-gzip (.tgz) files will have an associated .sha384 appended checksum of the desired download file.
-#### Type sharing
-You must make sure the [VNLib.Plugins](../Plugins/README.md) assembly is shared between the host and the plugin's load context's, otherwise there will be a Runtime Type mismatch and loading will fail. The *System.CoreLib* must also be shared (this may usually be handled by falling back to the default load context). Configuration data is (optionally) passed to the `IPlugin` with a serialized utf8 JSON binary buffer and assumes your instance will de-serialize the JSON configuration data. If it does, you may want to make sure the JSON library you are using is shared with the plugin assembly. This was changed to passing serialized JSON binary to support future changes and helping avoiding dependency hell by requiring System.Text.Json library be shared, however its not perfect at the moment.
+## Docs and Guides
+Documentation, specifications, and setup guides are available on my website.
-Finally, assuming you wish to use the `IPlugin` library for Http event processing, you will need to share the [VNLib.Net.Plugins](../Net.Http/readme.md) assembly, otherwise event handling will fail, and endpoints may not even register if these types are not shared.
+[Docs and Articles](https://www.vaughnnugent.com/resources/software/articles?tags=docs,_VNLib.Plugins.Runtime)
+[Builds and Source](https://www.vaughnnugent.com/resources/software/modules/VNLib.Core)
-#### Hot Reload
-Hot-reload is managed by this library if you wish to use it by setting the `IPluginConfig.WatchForReload` and the `IPluginConfig.ReloadDelay` properties correctly. Hot reload happens by watching the directory the assembly file resides for file changes. When a change has been detected, your `IPluginAssemblyLoader.Unload()` method is called and is expected to clean up resources and prepare for reloading. Unload may also be manually called if its enabled by the consumer of the `RuntimePluginLoader` instance.
-
-#### Unloading
-Unloading my be enabled, mutually exclusive to the hot-reload system. Which allows the consumer of the `RuntimePluginLoader` to manually unload plugin instances by calling `RuntimePluginLoader.UnloadAll()` and unload your `IPluginAssemblyLoader` instance, which it may then also load again at will. If unloading is disabled by your configuration calls to `RuntimePluginLoader.UnloadAll()` only unloads all plugin instances in the `PluginController` lifecycle controller. Loaded `IPlugin` instances are expected to be no longer in use and eligible for garbage collection after the `RuntimePluginLoader.UnloadAll()`, but this is only guaranteed if the consumer of the plugin respects the unload events and removes all references to ALL loaded types. (Hence the complexity of the event handling system)
-
-## Usage
-An XML documentation file is included for all public apis.
-
-### Consumer notes
-Dynamically loaded `IPlugin` instances are carefully wrapped behind multiple classes to help protect instances from improper consumption in an application, which may have undefined effects in your application. *Note* you should understand runtime assembly loading and how type isolation happens when loading via an `AssemblyLoadContext` paradigm. Plugin consumers are expected to abide by the lifecycle controller's api for proper usage. The lifecycle controller is 'event' driven, but requires registering event handlers, to avoid delegate memory leaks with a more *verbose* api (my preference). You should register your consumer event handlers before calling the `RuntimePluginLoader.LoadPlugins()` method to properly capture the `IPlugin` instance. It is safe to digest the `IPlugin` instance after this method is called by accessing the `plugin.Controller.Plugins` via the lifecycle controller. This method is **NOT** recommended, consumers should capture plugins via the event api and respect the load/unload events.
-
-When the unload event is fired from the lifecycle controller, all references to objects captured from the plugin are expected to be removed as soon as possible to make them eligible for garbage collection, and allow proper unloading.
-
-If you never intend to allow unloading, you may consume the `IPlugin` instances however you like as the protections provided by this library are not required or useful. If the type will never be unloaded, its safe to use everywhere in your application once its loaded.
-
-### Code
-```programming language C#
- //RuntimePluginLoader is disposable to cleanup optional config files and cleanup all resources
- using RuntimePluginLoader plugin = new(<yourAssemblyLoader>,<hostConfig>,<errorLogProvider>?);
-
- //Consumer may register an event handler to capture the on-load event to consume the plugin type
- plugin.Controller.Register(<consumerEventHandler>, <optional state>?);
-
- //Initializes the internal assemblyLoader, initializes the IPlugin instances into the lifecycle controller
- plugin.InitializeController();
-
- //Load all plugins that have been initialized and invokes registered loading event handlers
- plugin.LoadPlugins();
-
- //Safe to consume plugins directly from the lifecycle controller, but NOT recommended.
- plugin.Controller.Plugins.First().Plugin;
-
- //Trigger manual reload, will unload, then reload and trigger events
- plugin.ReloadPlugin();
-
- //Unload plugins only without unloading provider
- plugin.UnloadPlugins();
-
- //Unload all plugins and underlying IPluginAssemblyLoader
- plugin.UnloadAll();
-
- //Leaving scope disposes the loader
-```
-## Warnings
-
-#### Security concerns
-Plugins are required to be loading into the same AppDomain as the library consume (no remoting whatsoever) so care must be taken to understand where assemblies are loaded from, knowing the loaded code will have access to the entire AppDomain's memory.
-
-**Hot reload should only be enabled for debugging/development purposes, you should understand the security implications and compatibility of .NET collectable assemblies**
-
-With new api updates, you may consider verifying the plugin assembly (or its entire dependency chain) before loading it into the application domain.
-
-#### Consumer warnings
-Again, consumers are expected to respect plugin lifecycle events and properly remove references when the lifecycle controller notifies of an unload event.
-
-Unless event handling is unregistered, events will be raised any time a manual unload/load event is called. Meaning that while it is safe to continually call the `UnloadPlugins()` or the `UnloadAll()` method, events will be raised on every call, even though the `IPlugin` instance references have been destroyed within the lifecycle controller.
-
-It is safe to call `ReloadPlugins()` even after a `UnloadPlugins()` or `UnloadAll()` method has been called, however `ReloadPlugins()` method will raise exceptions if unloading is not enabled.
-
-## License
-The software in this repository is licensed under the GNU GPL version 2.0 (or any later version).
-See the LICENSE files for more information.
+## License
+The software in this repository is licensed under the GNU GPL version 2.0 (or any later version). See the LICENSE files for more information.
diff --git a/lib/Plugins.Runtime/build.readme.md b/lib/Plugins.Runtime/build.readme.txt
index e69de29..e69de29 100644
--- a/lib/Plugins.Runtime/build.readme.md
+++ b/lib/Plugins.Runtime/build.readme.txt
diff --git a/lib/Plugins.Runtime/src/VNLib.Plugins.Runtime.csproj b/lib/Plugins.Runtime/src/VNLib.Plugins.Runtime.csproj
index 362e1f1..ab8f547 100644
--- a/lib/Plugins.Runtime/src/VNLib.Plugins.Runtime.csproj
+++ b/lib/Plugins.Runtime/src/VNLib.Plugins.Runtime.csproj
@@ -51,7 +51,7 @@
<Pack>True</Pack>
<PackagePath>\</PackagePath>
</None>
- <None Include="..\LICENSE.txt">
+ <None Include="..\LICENSE">
<Pack>True</Pack>
<PackagePath>\</PackagePath>
</None>
diff --git a/lib/Net.Rest.Client/LICENSE.txt b/lib/Plugins/LICENSE
index 2848520..2848520 100644
--- a/lib/Net.Rest.Client/LICENSE.txt
+++ b/lib/Plugins/LICENSE
diff --git a/lib/Plugins/build.readme.md b/lib/Plugins/build.readme.txt
index e69de29..e69de29 100644
--- a/lib/Plugins/build.readme.md
+++ b/lib/Plugins/build.readme.txt
diff --git a/lib/Plugins/src/VNLib.Plugins.csproj b/lib/Plugins/src/VNLib.Plugins.csproj
index 51cdc20..e9aa10e 100644
--- a/lib/Plugins/src/VNLib.Plugins.csproj
+++ b/lib/Plugins/src/VNLib.Plugins.csproj
@@ -42,7 +42,7 @@
<Pack>True</Pack>
<PackagePath>\</PackagePath>
</None>
- <None Include="..\LICENSE.txt">
+ <None Include="..\LICENSE">
<Pack>True</Pack>
<PackagePath>\</PackagePath>
</None>
diff --git a/lib/Plugins.Runtime/LICENSE.txt b/lib/Utils.Memory/NativeHeapApi/LICENSE
index 2848520..2848520 100644
--- a/lib/Plugins.Runtime/LICENSE.txt
+++ b/lib/Utils.Memory/NativeHeapApi/LICENSE
diff --git a/lib/NativeHeapApi/README.md b/lib/Utils.Memory/NativeHeapApi/README.md
index 36d3a6e..36d3a6e 100644
--- a/lib/NativeHeapApi/README.md
+++ b/lib/Utils.Memory/NativeHeapApi/README.md
diff --git a/lib/NativeHeapApi/src/NativeHeapApi.h b/lib/Utils.Memory/NativeHeapApi/src/NativeHeapApi.h
index 5deca31..d70745b 100644
--- a/lib/NativeHeapApi/src/NativeHeapApi.h
+++ b/lib/Utils.Memory/NativeHeapApi/src/NativeHeapApi.h
@@ -84,7 +84,7 @@ typedef struct UnmanagedHeapDescriptor
{
LPVOID HeapPointer;
HeapCreationFlags CreationFlags;
- ERRNO Flags;
+ ERRNO Flags;
} UnmanagedHeapDescriptor;
/// <summary>
diff --git a/lib/Utils.Memory/vnlib_rpmalloc/CMakeLists.txt b/lib/Utils.Memory/vnlib_rpmalloc/CMakeLists.txt
new file mode 100644
index 0000000..84a0d16
--- /dev/null
+++ b/lib/Utils.Memory/vnlib_rpmalloc/CMakeLists.txt
@@ -0,0 +1,142 @@
+cmake_minimum_required(VERSION 3.0)
+
+project(vnlib_rpmalloc C)
+
+#export header files to the main project
+file(GLOB HEADERS *.h)
+
+#Add indepednent source files to the project
+set(VNLIB_RPMALLOC_SOURCES
+ "vnlib_rpmalloc.c"
+ "../rpmalloc/rpmalloc.c"
+)
+
+#add rpmalloc includes, there will only be one library
+include_directories(../rpmalloc)
+include_directories(../NativeHeapApi/src)
+
+#set options for greedy allocator defaults
+option(ENABLE_GREEDY "Enable greedy allocator configuration" ON)
+
+#create my shared library
+add_library(${CMAKE_PROJECT_NAME} SHARED ${VNLIB_RPMALLOC_SOURCES} ${HEADERS})
+#also create static library
+add_library(${CMAKE_PROJECT_NAME}_static STATIC ${VNLIB_RPMALLOC_SOURCES} ${HEADERS})
+
+#if on unix lib will be appended, so we can adjust
+if(UNIX)
+ set_target_properties(${CMAKE_PROJECT_NAME} ${CMAKE_PROJECT_NAME}_static PROPERTIES OUTPUT_NAME _rpmalloc)
+endif()
+
+#Setup the compiler options
+set(CMAKE_CXX_STANDARD 90)
+set(CMAKE_CXX_STANDARD_REQUIRED ON)
+set(DEFAULT_BUILD_TYPE "Release")
+
+#enable position independent code (for shared libraries with exports)
+set(CMAKE_POSITION_INDEPENDENT_CODE ON)
+
+message(STATUS "Build type is '${CMAKE_BUILD_TYPE}'")
+
+#if debug
+add_compile_definitions($<$<CONFIG:Debug>:DEBUG>)
+
+if(ENABLE_GREEDY)
+ add_compile_definitions(VNLIB_RPMALLOC_GREEDY)
+endif()
+
+#setup flags for windows compilation
+if(MSVC)
+
+ #global windows cl flags
+ add_compile_options(
+ /Qspectre
+ /sdl
+ /TC
+ /GS
+ /machine:x64
+
+ $<$<CONFIG:Debug>:/FC>
+ $<$<CONFIG:Debug>:/showIncludes>
+ )
+
+ #only target our project
+ target_compile_options(
+ ${CMAKE_PROJECT_NAME}
+ PRIVATE
+
+ #disable warnings for struct padding and spectre mitigation wuen WX is enabled
+ $<$<CONFIG:Debug>:/wd5045>
+ $<$<CONFIG:Debug>:/wd4820>
+ $<$<CONFIG:Debug>:/wd4574>
+
+ #for debug configs
+ $<$<CONFIG:Debug>:/options:strict>
+ #disable warnings for struct padding and spectre mitigation wuen WX is enabled
+ $<$<CONFIG:Debug>:/Wall>
+ $<$<CONFIG:Debug>:/WX> #warnings as errors (only for our project)
+ $<$<CONFIG:Debug>:/Zi>
+ $<$<CONFIG:Debug>:/Zo>
+ )
+
+ #set build macros
+ add_compile_definitions(
+ $<$<CONFIG:DEBUG>:DEBUG>
+ $<$<CONFIG:RELEASE>:RELEASE>
+ )
+
+#configure gcc flags
+elseif(CMAKE_COMPILER_IS_GNUCC)
+
+ add_compile_options(
+ -Wextra
+ -fstack-protector
+
+ $<$<CONFIG:Debug>:-g>
+ $<$<CONFIG:Debug>:-Og>
+ $<$<CONFIG:Debug>:-Wall>
+ $<$<CONFIG:Debug>:-Werror>
+ )
+
+ #only target our project
+ target_compile_options(
+ ${CMAKE_PROJECT_NAME}
+ PRIVATE
+ $<$<CONFIG:Debug>:-Wall>
+ $<$<CONFIG:Debug>:-pedantic>
+ )
+
+endif()
+
+#enable required features
+add_definitions(-DRPMALLOC_FIRST_CLASS_HEAPS=1)
+add_definitions(-DENABLE_ADAPTIVE_THREAD_CACHE=1)
+
+#add some debugging/tracing for debug mode
+add_compile_definitions($<$<CONFIG:Debug>:ENABLE_VALIDATE_ARGS=1>)
+add_compile_definitions($<$<CONFIG:Debug>:ENABLE_ASSERTS=1>)
+
+if(ENABLE_GREEDY)
+
+#if greedy is enabled, add greedy options
+add_definitions(-DENABLE_UNLIMITED_CACHE=1)
+add_definitions(-DENABLE_UNLIMITED_GLOBAL_CACHE=1)
+add_definitions(-DENABLE_UNLIMITED_THREAD_CACHE=1)
+
+#On by default but we otherwise disable global cache to really reduce commited size
+add_definitions(-DENABLE_GLOBAL_CACHE=1)
+add_definitions(-DENABLE_UNLIMITED_GLOBAL_CACHE=1)
+
+else()
+
+#disable greedy definitions
+add_definitions(-DENABLE_UNLIMITED_CACHE 0)
+add_definitions(-DENABLE_UNLIMITED_GLOBAL_CACHE=0)
+add_definitions(-DENABLE_UNLIMITED_THREAD_CACHE=0)
+add_definitions(-DENABLE_GLOBAL_CACHE=0)
+
+#also disable unlimited global cache to release spans to OS
+add_definitions(-DENABLE_UNLIMITED_GLOBAL_CACHE=0)
+
+endif()
+
diff --git a/lib/Utils/LICENSE.txt b/lib/Utils.Memory/vnlib_rpmalloc/LICENSE
index cbb3969..ce09686 100644
--- a/lib/Utils/LICENSE.txt
+++ b/lib/Utils.Memory/vnlib_rpmalloc/LICENSE
@@ -1,8 +1,8 @@
-Copyright (c) 2022 Vaughn Nugent
+Copyright (c) 2023 Vaughn Nugent
Contact information
Name: Vaughn Nugent
- Email: public[at]vaughnnugent[dot]com
+ Email: vnpublic[at]proton.me
Website: https://www.vaughnnugent.com
The software in this repository is licensed under the GNU GPL version 2.0 (or any later version).
diff --git a/lib/Utils.Memory/vnlib_rpmalloc/Taskfile.yaml b/lib/Utils.Memory/vnlib_rpmalloc/Taskfile.yaml
new file mode 100644
index 0000000..d7d921a
--- /dev/null
+++ b/lib/Utils.Memory/vnlib_rpmalloc/Taskfile.yaml
@@ -0,0 +1,73 @@
+# https://taskfile.dev
+
+#Called by the vnbuild system to produce builds for my website
+#https://www.vaughnnugent.com/resources/software
+
+#This taskfile is called in this directory and is specific to the vnlib_rpmalloc project
+#that handles the MSBuild outside of the solution file
+
+version: '3'
+
+vars:
+ INT_DIR: '{{.SCRATCH_DIR}}/obj/{{.MODULE_NAME}}/'
+ MS_ARGS: '/p:Platform=x64 /p:RunAnalyzersDuringBuild=false /p:BuildInParallel=true /p:MultiProcessorCompilation=true'
+
+tasks:
+
+ build:
+ cmds:
+ #init cmake build with greedy enabled
+ - cmake -B./build -DENABLE_GREEDY=1
+
+ #build solution in debug mode
+ - cd build && msbuild {{.PROJECT_NAME}}.sln /p:Configuration=debug {{.BUILD_FLAGS}} {{.MS_ARGS}}
+
+ #build in release
+ - cd build && msbuild {{.PROJECT_NAME}}.sln /p:Configuration=release {{.BUILD_FLAGS}} {{.MS_ARGS}}
+
+ postbuild_success:
+ vars:
+ #required files to include in tar
+ TAR_FILES: "license.txt readme.txt rpmalloc_license.txt"
+
+ cmds:
+ #make bin dir
+ - cmd: powershell -Command "New-Item -Type Directory -Force -Path './bin'"
+ ignore_error: true
+
+ #get licenses for debug
+ - task: licenses
+ vars:
+ TARGET: './build/Debug'
+
+ - task: licenses
+ vars:
+ TARGET: './build/Release'
+
+
+ #static debug lib
+ - cd build/Debug && tar -czf '../../bin/win-x64-debug-{{.PROJECT_NAME}}-static.tgz' {{.PROJECT_NAME}}_static.lib {{.TAR_FILES}} {{.PROJECT_NAME}}_static.pdb
+ #dynamic debug lib
+ - cd build/Debug && tar -czf '../../bin/win-x64-debug-{{.PROJECT_NAME}}.tgz' {{.PROJECT_NAME}}.dll {{.TAR_FILES}} {{.PROJECT_NAME}}.pdb
+
+ #release static lib
+ - cd build/Release && tar -czf '../../bin/win-x64-release-{{.PROJECT_NAME}}-static.tgz' {{.PROJECT_NAME}}_static.lib {{.TAR_FILES}}
+ #release dll
+ - cd build/Release && tar -czf '../../bin/win-x64-release-{{.PROJECT_NAME}}.tgz' {{.PROJECT_NAME}}.dll {{.TAR_FILES}}
+
+
+ licenses:
+ cmds:
+ #add rpmalloc license to binary output
+ - powershell -Command "Copy-Item -Path ../rpmalloc/license -Destination '{{.TARGET}}/rpmalloc_license.txt'"
+ #add my license file
+ - powershell -Command "Copy-Item -Path ./license -Destination '{{.TARGET}}/license.txt'"
+ #add readme file
+ - powershell -Command "Copy-Item -Path ./build.readme.txt -Destination '{{.TARGET}}/readme.txt'"
+
+
+ clean:
+ ignore_error: true
+ cmds:
+ - cmd: powershell -Command "Remove-Item -Recurse './bin'"
+ - cmd: powershell -Command "Remove-Item -Recurse './build'" \ No newline at end of file
diff --git a/lib/Utils/build.readme.md b/lib/Utils.Memory/vnlib_rpmalloc/build.readme.txt
index e69de29..e69de29 100644
--- a/lib/Utils/build.readme.md
+++ b/lib/Utils.Memory/vnlib_rpmalloc/build.readme.txt
diff --git a/lib/Utils.Memory/vnlib_rpmalloc/package.json b/lib/Utils.Memory/vnlib_rpmalloc/package.json
new file mode 100644
index 0000000..4cc7e68
--- /dev/null
+++ b/lib/Utils.Memory/vnlib_rpmalloc/package.json
@@ -0,0 +1,10 @@
+{
+ "name": "vnlib_rpmalloc",
+ "version": "0.1.3",
+ "output_dir": "bin",
+ "author": "Vaughn Nugent",
+ "description": "A project to maintain an x64 Windows dynamic and static library for RpMalloc by Mattias Jansson for use with the NativeHeapApi to for VNLib.Utils native heap loading.",
+ "copyright": "Copyright \u00A9 2023 Vaughn Nugent",
+ "company": "Vaughn Nugent",
+ "repository": "https://github.com/VnUgE/VNLib.Core/tree/main/lib/Utils.Memory/vnlib_rpmalloc"
+} \ No newline at end of file
diff --git a/lib/WinRpMalloc/src/dllmain.c b/lib/Utils.Memory/vnlib_rpmalloc/vnlib_rpmalloc.c
index 58f5538..5daa042 100644
--- a/lib/WinRpMalloc/src/dllmain.c
+++ b/lib/Utils.Memory/vnlib_rpmalloc/vnlib_rpmalloc.c
@@ -2,47 +2,54 @@
* Copyright (c) 2023 Vaughn Nugent
*
* Library: VNLib
-* Package: WinRpMalloc
-* File: dllmain.c
+* Package: vnlib_rpmalloc
+* File: vnlib_rpmalloc.c
*
-* WinRpMalloc is free software: you can redistribute it and/or modify
+* framework.h is part of vnlib_rpmalloc which is part of the larger
+* VNLib collection of libraries and utilities.
+*
+* vnlib_rpmalloc is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published
* by the Free Software Foundation, either version 2 of the License,
* or (at your option) any later version.
*
-* WinRpMalloc is distributed in the hope that it will be useful,
+* vnlib_rpmalloc is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
-* along with WinRpMalloc. If not, see http://www.gnu.org/licenses/.
+* along with vnlib_rpmalloc. If not, see http://www.gnu.org/licenses/.
*/
-#include "pch.h"
-//Include the native heap header directly from its repo location
-#include "../../NativeHeapApi/src/NativeHeapApi.h"
+
+#include "vnlib_rpmalloc.h"
+#include <NativeHeapApi.h>
+#include <rpmalloc.h>
+#include <stdint.h>
BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
{
- /*
+ (void)hModule;
+ (void)lpReserved;
+ /*
* Taken from the malloc.c file for initializing the library.
* and thread events
*/
switch (ul_reason_for_call)
{
- case DLL_PROCESS_ATTACH:
- rpmalloc_initialize();
- break;
- case DLL_THREAD_ATTACH:
- rpmalloc_thread_initialize();
- break;
- case DLL_THREAD_DETACH:
- rpmalloc_thread_finalize(1);
- break;
- case DLL_PROCESS_DETACH:
- rpmalloc_finalize();
- break;
+ case DLL_PROCESS_ATTACH:
+ rpmalloc_initialize();
+ break;
+ case DLL_THREAD_ATTACH:
+ rpmalloc_thread_initialize();
+ break;
+ case DLL_THREAD_DETACH:
+ rpmalloc_thread_finalize(1);
+ break;
+ case DLL_PROCESS_DETACH:
+ rpmalloc_finalize();
+ break;
}
return TRUE;
}
@@ -64,9 +71,9 @@ HEAP_METHOD_EXPORT ERRNO HEAP_METHOD_CC heapCreate(UnmanagedHeapDescriptor* flag
flags->HeapPointer = (LPVOID)GLOBAL_HEAP_HANDLE_VALUE;
//Success
- return TRUE;
+ return (ERRNO)TRUE;
}
-
+
//Allocate a first class heap
flags->HeapPointer = rpmalloc_heap_acquire();
@@ -80,10 +87,10 @@ HEAP_METHOD_EXPORT ERRNO HEAP_METHOD_CC heapCreate(UnmanagedHeapDescriptor* flag
HEAP_METHOD_EXPORT ERRNO HEAP_METHOD_CC heapDestroy(LPVOID heap)
{
//Destroy the heap
- if ((int)heap == GLOBAL_HEAP_HANDLE_VALUE)
+ if ((int64_t)heap == GLOBAL_HEAP_HANDLE_VALUE)
{
//Gloal heap, do nothing, and allow the entrypoint cleanup
- return TRUE;
+ return (ERRNO)TRUE;
}
//Free all before destroy
@@ -92,7 +99,7 @@ HEAP_METHOD_EXPORT ERRNO HEAP_METHOD_CC heapDestroy(LPVOID heap)
//Destroy the heap
rpmalloc_heap_release(heap);
- return TRUE;
+ return (ERRNO)TRUE;
}
@@ -102,8 +109,8 @@ HEAP_METHOD_EXPORT LPVOID HEAP_METHOD_CC heapAlloc(LPVOID heap, size_t elements,
size_t size = elements * alignment;
//Check for global heap
- if ((int)heap == GLOBAL_HEAP_HANDLE_VALUE)
- {
+ if ((int64_t)heap == GLOBAL_HEAP_HANDLE_VALUE)
+ {
/*
* When called from the dotnet CLR the thread may not call the DLL
* thread attach method, so we need to check and initialze the heap
@@ -111,22 +118,22 @@ HEAP_METHOD_EXPORT LPVOID HEAP_METHOD_CC heapAlloc(LPVOID heap, size_t elements,
*/
GLOBAL_HEAP_INIT_CHECK
- //Allocate the block
- if (zero)
- {
- //Calloc
- return rpcalloc(elements, alignment);
- }
- else
- {
- //Alloc without zero
- return rpmalloc(size);
- }
+ //Allocate the block
+ if (zero)
+ {
+ //Calloc
+ return rpcalloc(elements, alignment);
+ }
+ else
+ {
+ //Alloc without zero
+ return rpmalloc(size);
+ }
}
else
{
//First class heap, lock is held by caller, optionally zero the block
- if (zero)
+ if (zero)
{
return rpmalloc_heap_calloc(heap, alignment, elements);
}
@@ -142,9 +149,10 @@ HEAP_METHOD_EXPORT LPVOID HEAP_METHOD_CC heapRealloc(LPVOID heap, LPVOID block,
{
//Multiply for element size
size_t size = elements * alignment;
+ (void)zero;
//Check for global heap
- if ((int)heap == GLOBAL_HEAP_HANDLE_VALUE)
+ if ((int64_t)heap == GLOBAL_HEAP_HANDLE_VALUE)
{
/*
* When called from the dotnet CLR the thread may not call the DLL
@@ -153,8 +161,8 @@ HEAP_METHOD_EXPORT LPVOID HEAP_METHOD_CC heapRealloc(LPVOID heap, LPVOID block,
*/
GLOBAL_HEAP_INIT_CHECK
- //Calloc
- return rprealloc(block, size);
+ //Calloc
+ return rprealloc(block, size);
}
else
{
@@ -167,17 +175,17 @@ HEAP_METHOD_EXPORT LPVOID HEAP_METHOD_CC heapRealloc(LPVOID heap, LPVOID block,
HEAP_METHOD_EXPORT ERRNO HEAP_METHOD_CC heapFree(LPVOID heap, LPVOID block)
{
//Check for global heap
- if ((int)heap == GLOBAL_HEAP_HANDLE_VALUE)
+ if ((int64_t)heap == GLOBAL_HEAP_HANDLE_VALUE)
{
/*
* If free happens on a different thread, we must allocate the heap
- * its cheap to check
+ * its cheap to check
*/
GLOBAL_HEAP_INIT_CHECK
- //free block
- rpfree(block);
+ //free block
+ rpfree(block);
}
else
{
@@ -185,5 +193,5 @@ HEAP_METHOD_EXPORT ERRNO HEAP_METHOD_CC heapFree(LPVOID heap, LPVOID block)
rpmalloc_heap_free(heap, block);
}
- return TRUE;
+ return (ERRNO)TRUE;
} \ No newline at end of file
diff --git a/lib/Utils.Memory/vnlib_rpmalloc/vnlib_rpmalloc.h b/lib/Utils.Memory/vnlib_rpmalloc/vnlib_rpmalloc.h
new file mode 100644
index 0000000..0b89580
--- /dev/null
+++ b/lib/Utils.Memory/vnlib_rpmalloc/vnlib_rpmalloc.h
@@ -0,0 +1,11 @@
+
+#pragma once
+#ifndef VNLIB_RPMALLOC_H
+
+#if defined(_WIN32) || defined(_WIN64)
+#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
+// Windows Header Files
+#include <windows.h>
+#endif
+
+#endif // !VNLIB_RPMALLOC_H \ No newline at end of file
diff --git a/lib/Utils.Memory/vnlib_rpmalloc/vnlib_rpmalloc.vcxitems b/lib/Utils.Memory/vnlib_rpmalloc/vnlib_rpmalloc.vcxitems
new file mode 100644
index 0000000..2e22921
--- /dev/null
+++ b/lib/Utils.Memory/vnlib_rpmalloc/vnlib_rpmalloc.vcxitems
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <PropertyGroup Label="Globals">
+ <MSBuildAllProjects Condition="'$(MSBuildVersion)' == '' Or '$(MSBuildVersion)' &lt; '16.0'">$(MSBuildAllProjects);$(MSBuildThisFileFullPath)</MSBuildAllProjects>
+ <HasSharedItems>true</HasSharedItems>
+ <ItemsProjectGuid>{194aad38-05ab-4715-a367-190b3da78899}</ItemsProjectGuid>
+ </PropertyGroup>
+ <ItemDefinitionGroup>
+ <ClCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(MSBuildThisFileDirectory)</AdditionalIncludeDirectories>
+ </ClCompile>
+ </ItemDefinitionGroup>
+ <ItemGroup>
+ <ProjectCapability Include="SourceItemsFromImports" />
+ </ItemGroup>
+ <ItemGroup>
+ <Text Include="$(MSBuildThisFileDirectory)build.readme.txt" />
+ <Text Include="$(MSBuildThisFileDirectory)CMakeLists.txt" />
+ <Text Include="$(MSBuildThisFileDirectory)license.txt" />
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Include="$(MSBuildThisFileDirectory)vnlib_rpmalloc.h" />
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="$(MSBuildThisFileDirectory)vnlib_rpmalloc.c" />
+ </ItemGroup>
+ <ItemGroup>
+ <None Include="$(MSBuildThisFileDirectory)package.json" />
+ <None Include="$(MSBuildThisFileDirectory)Taskfile.yaml" />
+ </ItemGroup>
+</Project> \ No newline at end of file
diff --git a/lib/WinRpMalloc/LICENSE.txt b/lib/Utils/LICENSE
index 2848520..ce09686 100644
--- a/lib/WinRpMalloc/LICENSE.txt
+++ b/lib/Utils/LICENSE
@@ -1,3 +1,10 @@
+Copyright (c) 2023 Vaughn Nugent
+
+Contact information
+ Name: Vaughn Nugent
+ Email: vnpublic[at]proton.me
+ Website: https://www.vaughnnugent.com
+
The software in this repository is licensed under the GNU GPL version 2.0 (or any later version).
SPDX-License-Identifier: GPL-2.0-or-later
@@ -283,64 +290,4 @@ YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
- END OF TERMS AND CONDITIONS
-
- How to Apply These Terms to Your New Programs
-
- If you develop a new program, and you want it to be of the greatest
-possible use to the public, the best way to achieve this is to make it
-free software which everyone can redistribute and change under these terms.
-
- To do so, attach the following notices to the program. It is safest
-to attach them to the start of each source file to most effectively
-convey the exclusion of warranty; and each file should have at least
-the "copyright" line and a pointer to where the full notice is found.
-
- VNLib.Hashing.Portable is a compact .NET managed cryptographic operation
- utilities library.
- Copyright (C) 2022 Vaughn Nugent
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along
- with this program; if not, write to the Free Software Foundation, Inc.,
- 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
-
-Also add information on how to contact you by electronic and paper mail.
-
-If the program is interactive, make it output a short notice like this
-when it starts in an interactive mode:
-
- Gnomovision version 69, Copyright (C) year name of author
- Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
- This is free software, and you are welcome to redistribute it
- under certain conditions; type `show c' for details.
-
-The hypothetical commands `show w' and `show c' should show the appropriate
-parts of the General Public License. Of course, the commands you use may
-be called something other than `show w' and `show c'; they could even be
-mouse-clicks or menu items--whatever suits your program.
-
-You should also get your employer (if you work as a programmer) or your
-school, if any, to sign a "copyright disclaimer" for the program, if
-necessary. Here is a sample; alter the names:
-
- Yoyodyne, Inc., hereby disclaims all copyright interest in the program
- `Gnomovision' (which makes passes at compilers) written by James Hacker.
-
- <signature of Ty Coon>, 1 April 1989
- Ty Coon, President of Vice
-
-This General Public License does not permit incorporating your program into
-proprietary programs. If your program is a subroutine library, you may
-consider it more useful to permit linking proprietary applications with the
-library. If this is what you want to do, use the GNU Lesser General
-Public License instead of this License. \ No newline at end of file
+ END OF TERMS AND CONDITIONS \ No newline at end of file
diff --git a/lib/WinRpMalloc/build.readme.md b/lib/Utils/build.readme.txt
index e69de29..e69de29 100644
--- a/lib/WinRpMalloc/build.readme.md
+++ b/lib/Utils/build.readme.txt
diff --git a/lib/Utils/src/VNLib.Utils.csproj b/lib/Utils/src/VNLib.Utils.csproj
index 12e6a5e..404beaa 100644
--- a/lib/Utils/src/VNLib.Utils.csproj
+++ b/lib/Utils/src/VNLib.Utils.csproj
@@ -31,7 +31,7 @@
<Pack>True</Pack>
<PackagePath>\</PackagePath>
</None>
- <None Include="..\LICENSE.txt">
+ <None Include="..\LICENSE">
<Pack>True</Pack>
<PackagePath>\</PackagePath>
</None>
diff --git a/lib/WinRpMalloc/README.md b/lib/WinRpMalloc/README.md
deleted file mode 100644
index 29164cf..0000000
--- a/lib/WinRpMalloc/README.md
+++ /dev/null
@@ -1,16 +0,0 @@
-# WinRpMalloc
-
-*A project to maintain a Windows dll for RpMalloc by Mattias Jansson with some basic defaults for .NET loading*
-
-#### Builds
-Debug build w/ symbols & xml docs, release builds, and individually packaged source code are available on my [website](https://www.vaughnnugent.com/resources/software). All tar-gzip (.tgz) files will have an associated .sha384 appended checksum of the desired download file.
-
-## RPMalloc
-
-[**RPMalloc**](https://github.com/mjansson/rpmalloc) By Mattias Jansson - A cross-platform, lock-free, efficient memory allocator.
-
-
-#### Notes
-This project exists to maintain a working clone of of the RpMalloc library specifically to produce a Windows 64-bit native library that exposes the api for use by runtimes such as Microsft .NET.
-
-You may wish to collect the source code and build the library yourself directly from Mattias's. \ No newline at end of file
diff --git a/lib/WinRpMalloc/Taskfile.yaml b/lib/WinRpMalloc/Taskfile.yaml
deleted file mode 100644
index 356db70..0000000
--- a/lib/WinRpMalloc/Taskfile.yaml
+++ /dev/null
@@ -1,73 +0,0 @@
-# https://taskfile.dev
-
-#Called by the vnbuild system to produce builds for my website
-#https://www.vaughnnugent.com/resources/software
-
-#This taskfile is called in this directory and is specific to the WinRpMalloc project
-#that handles the MSBuild outside of the solution file
-
-version: '3'
-
-vars:
- RPMALLOC_LICENSE: 'https://raw.githubusercontent.com/mjansson/rpmalloc/develop/LICENSE'
- INT_DIR: '{{.SCRATCH_DIR}}/obj/{{.MODULE_NAME}}/'
- MS_ARGS: '/p:Platform=x64 /p:RunAnalyzersDuringBuild=false /p:IntermediateOutputPath="{{.INT_DIR}}" /p:UseCommonOutputDirectory=true /p:BuildInParallel=true /p:MultiProcessorCompilation=true'
-
-tasks:
-
- build:
- #build from the src directory
- dir: '{{.USER_WORKING_DIR}}'
- cmds:
- #build in debug mode
- - msbuild /p:Configuration=debug {{.BUILD_FLAGS}} {{.MS_ARGS}}
- #build in release
- - msbuild /p:Configuration=release {{.BUILD_FLAGS}} {{.MS_ARGS}}
-
- postbuild_success:
- vars:
- TARGET: '{{.USER_WORKING_DIR}}/bin'
-
- cmds:
- #create the target directory
- - powershell -Command "New-Item -Type Directory -Force -Path '{{.TARGET}}'"
-
- #remove uncessary files from outputs
- - powershell -Command "Get-ChildItem -Recurse './src/x64/*' -Include *.log,*.recipe,*.CopyComplete,*.json,*.FileListAbsolute.txt | Remove-Item"
- - powershell -Command "Get-ChildItem '*.tlog' -Recurse * | Remove-Item"
-
- #run debug and release post
- - task: postbuild
- vars: { BUILD_MODE: debug }
-
- - task: postbuild
- vars: { BUILD_MODE: release }
-
- #tar input and output
- - cd ./src/x64/debug && tar -czf "{{.TARGET}}/debug.tgz" .
-
- #capture only dll, license, + readme files on release
- - cd ./src/x64/release && tar --include='*.dll' --include='license.txt' --include='readme.md' --include='rpmalloc_license.txt' -czf "{{.TARGET}}/release.tgz" *
-
-
- postbuild:
- vars:
- TARGET: './src/x64/{{.BUILD_MODE}}'
-
- cmds:
- #add rpmalloc license to binary output
- - powershell -Command "Invoke-WebRequest '{{.RPMALLOC_LICENSE}}' -Outfile '{{.TARGET}}/rpmalloc_license.txt'"
-
- #add my license file
- - powershell -Command "Copy-Item -Path ./LICENSE.txt -Destination '{{.TARGET}}/license.txt'"
-
- #add readme file
- - powershell -Command "Copy-Item -Path ./build.readme.md -Destination '{{.TARGET}}/readme.md'"
-
-
- clean:
- cmds:
- - cmd: powershell -Command "Remove-Item -Recurse './src/x64' -ErrorAction SilentlyContinue"
- ignore_error: true
- - cmd: powershell -Command "Remove-Item -Recurse './src/bin' -ErrorAction SilentlyContinue"
- ignore_error: true \ No newline at end of file
diff --git a/lib/WinRpMalloc/src/WinRpMalloc.vcxproj b/lib/WinRpMalloc/src/WinRpMalloc.vcxproj
deleted file mode 100644
index 7322319..0000000
--- a/lib/WinRpMalloc/src/WinRpMalloc.vcxproj
+++ /dev/null
@@ -1,177 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
- <PropertyGroup>
- <VCToolsInstallDir>C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.34.31933\</VCToolsInstallDir>
- </PropertyGroup>
- <ItemGroup Label="ProjectConfigurations">
- <ProjectConfiguration Include="Debug|Win32">
- <Configuration>Debug</Configuration>
- <Platform>Win32</Platform>
- </ProjectConfiguration>
- <ProjectConfiguration Include="Release|Win32">
- <Configuration>Release</Configuration>
- <Platform>Win32</Platform>
- </ProjectConfiguration>
- <ProjectConfiguration Include="Debug|x64">
- <Configuration>Debug</Configuration>
- <Platform>x64</Platform>
- </ProjectConfiguration>
- <ProjectConfiguration Include="Release|x64">
- <Configuration>Release</Configuration>
- <Platform>x64</Platform>
- </ProjectConfiguration>
- </ItemGroup>
- <PropertyGroup Label="Globals">
- <VCProjectVersion>16.0</VCProjectVersion>
- <Keyword>Win32Proj</Keyword>
- <ProjectGuid>{f5bfb8aa-a436-4a8d-94bc-9eff3ad8aa1d}</ProjectGuid>
- <RootNamespace>WinRpMalloc</RootNamespace>
- <WindowsTargetPlatformVersion>10.0.20348.0</WindowsTargetPlatformVersion>
- </PropertyGroup>
- <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
- <ConfigurationType>DynamicLibrary</ConfigurationType>
- <UseDebugLibraries>true</UseDebugLibraries>
- <PlatformToolset>v143</PlatformToolset>
- <CharacterSet>Unicode</CharacterSet>
- </PropertyGroup>
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
- <ConfigurationType>DynamicLibrary</ConfigurationType>
- <UseDebugLibraries>false</UseDebugLibraries>
- <PlatformToolset>v143</PlatformToolset>
- <WholeProgramOptimization>true</WholeProgramOptimization>
- <CharacterSet>Unicode</CharacterSet>
- </PropertyGroup>
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
- <ConfigurationType>DynamicLibrary</ConfigurationType>
- <PlatformToolset>v143</PlatformToolset>
- <UseOfMfc>false</UseOfMfc>
- <UseDebugLibraries>true</UseDebugLibraries>
- </PropertyGroup>
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
- <ConfigurationType>DynamicLibrary</ConfigurationType>
- <UseDebugLibraries>false</UseDebugLibraries>
- <PlatformToolset>v143</PlatformToolset>
- <WholeProgramOptimization>true</WholeProgramOptimization>
- <CharacterSet>Unicode</CharacterSet>
- </PropertyGroup>
- <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
- <ImportGroup Label="ExtensionSettings">
- </ImportGroup>
- <ImportGroup Label="Shared">
- </ImportGroup>
- <PropertyGroup Label="UserMacros" />
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
- <LinkIncremental>true</LinkIncremental>
- </PropertyGroup>
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
- <LinkIncremental>false</LinkIncremental>
- </PropertyGroup>
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
- <CopyCppRuntimeToOutputDir>true</CopyCppRuntimeToOutputDir>
- <OutDir>$(ProjectDir)$(Platform)\$(Configuration)\</OutDir>
- <TargetName>rpmalloc</TargetName>
- </PropertyGroup>
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
- <LinkIncremental>false</LinkIncremental>
- <TargetName>rpmalloc</TargetName>
- </PropertyGroup>
- <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
- <ClCompile>
- <WarningLevel>Level3</WarningLevel>
- <SDLCheck>true</SDLCheck>
- <PreprocessorDefinitions>WIN32;_DEBUG;WINRPMALLOC_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
- <ConformanceMode>true</ConformanceMode>
- <PrecompiledHeader>Use</PrecompiledHeader>
- <PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
- </ClCompile>
- <Link>
- <SubSystem>Windows</SubSystem>
- <GenerateDebugInformation>true</GenerateDebugInformation>
- <EnableUAC>false</EnableUAC>
- </Link>
- </ItemDefinitionGroup>
- <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
- <ClCompile>
- <WarningLevel>Level3</WarningLevel>
- <FunctionLevelLinking>true</FunctionLevelLinking>
- <IntrinsicFunctions>true</IntrinsicFunctions>
- <SDLCheck>true</SDLCheck>
- <PreprocessorDefinitions>WIN32;NDEBUG;WINRPMALLOC_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
- <ConformanceMode>true</ConformanceMode>
- <PrecompiledHeader>Use</PrecompiledHeader>
- <PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
- </ClCompile>
- <Link>
- <SubSystem>Windows</SubSystem>
- <EnableCOMDATFolding>true</EnableCOMDATFolding>
- <OptimizeReferences>true</OptimizeReferences>
- <GenerateDebugInformation>true</GenerateDebugInformation>
- <EnableUAC>false</EnableUAC>
- </Link>
- </ItemDefinitionGroup>
- <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
- <ClCompile>
- <WarningLevel>EnableAllWarnings</WarningLevel>
- <SDLCheck>true</SDLCheck>
- <PreprocessorDefinitions>_DEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
- <ConformanceMode>true</ConformanceMode>
- <PrecompiledHeader>Use</PrecompiledHeader>
- <PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
- <LanguageStandard_C>stdc17</LanguageStandard_C>
- <CallingConvention>StdCall</CallingConvention>
- <MultiProcessorCompilation>true</MultiProcessorCompilation>
- <FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>
- <GenerateSourceDependencies>true</GenerateSourceDependencies>
- <BasicRuntimeChecks>Default</BasicRuntimeChecks>
- <MinimalRebuild>false</MinimalRebuild>
- <CompileAs>CompileAsC</CompileAs>
- <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
- </ClCompile>
- <Link>
- <GenerateDebugInformation>true</GenerateDebugInformation>
- <Version>
- </Version>
- <LargeAddressAware>true</LargeAddressAware>
- <SubSystem>Windows</SubSystem>
- </Link>
- </ItemDefinitionGroup>
- <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
- <ClCompile>
- <WarningLevel>Level3</WarningLevel>
- <FunctionLevelLinking>true</FunctionLevelLinking>
- <IntrinsicFunctions>true</IntrinsicFunctions>
- <SDLCheck>true</SDLCheck>
- <PreprocessorDefinitions>NDEBUG;WINRPMALLOC_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
- <ConformanceMode>true</ConformanceMode>
- <PrecompiledHeader>Use</PrecompiledHeader>
- <PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
- </ClCompile>
- <Link>
- <SubSystem>Windows</SubSystem>
- <EnableCOMDATFolding>true</EnableCOMDATFolding>
- <OptimizeReferences>true</OptimizeReferences>
- <GenerateDebugInformation>true</GenerateDebugInformation>
- <EnableUAC>false</EnableUAC>
- </Link>
- </ItemDefinitionGroup>
- <ItemGroup>
- <ClInclude Include="..\..\NativeHeapApi\src\NativeHeapApi.h" />
- <ClInclude Include="framework.h" />
- <ClInclude Include="pch.h" />
- <ClInclude Include="rpmalloc.h" />
- </ItemGroup>
- <ItemGroup>
- <ClCompile Include="dllmain.c" />
- <ClCompile Include="pch.c">
- <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Create</PrecompiledHeader>
- <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Create</PrecompiledHeader>
- <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Create</PrecompiledHeader>
- <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Create</PrecompiledHeader>
- </ClCompile>
- <ClCompile Include="rpmalloc.c" />
- </ItemGroup>
- <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
- <ImportGroup Label="ExtensionTargets">
- </ImportGroup>
-</Project> \ No newline at end of file
diff --git a/lib/WinRpMalloc/src/framework.h b/lib/WinRpMalloc/src/framework.h
deleted file mode 100644
index 573886e..0000000
--- a/lib/WinRpMalloc/src/framework.h
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
-* Copyright (c) 2022 Vaughn Nugent
-*
-* Library: VNLib
-* Package: WinRpMalloc
-* File: framework.h
-*
-* framework.h is part of WinRpMalloc which is part of the larger
-* VNLib collection of libraries and utilities.
-*
-* WinRpMalloc is free software: you can redistribute it and/or modify
-* it under the terms of the GNU General Public License as published
-* by the Free Software Foundation, either version 2 of the License,
-* or (at your option) any later version.
-*
-* WinRpMalloc is distributed in the hope that it will be useful,
-* but WITHOUT ANY WARRANTY; without even the implied warranty of
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-* General Public License for more details.
-*
-* You should have received a copy of the GNU General Public License
-* along with WinRpMalloc. If not, see http://www.gnu.org/licenses/.
-*/
-
-#pragma once
-
-#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
-// Windows Header Files
-#include <windows.h>
diff --git a/lib/WinRpMalloc/src/package.json b/lib/WinRpMalloc/src/package.json
deleted file mode 100644
index 6470e01..0000000
--- a/lib/WinRpMalloc/src/package.json
+++ /dev/null
@@ -1,9 +0,0 @@
-{
- "name": "WinRpMalloc",
- "version": "0.1.2",
- "author": "Vaughn Nugent",
- "description": "A project to maintain an x64 Windows dll for RpMalloc by Mattias Jansson with some basic defaults for .NET loading. The debug output contains the debug MVCR libs and debug symbols.",
- "copyright": "Copyright \u00A9 2023 Vaughn Nugent",
- "company": "Vaughn Nugent",
- "repository": "https://github.com/VnUgE/VNLib.Core/tree/main/lib/WinRpMalloc"
-} \ No newline at end of file
diff --git a/lib/WinRpMalloc/src/pch.c b/lib/WinRpMalloc/src/pch.c
deleted file mode 100644
index 64b7eef..0000000
--- a/lib/WinRpMalloc/src/pch.c
+++ /dev/null
@@ -1,5 +0,0 @@
-// pch.cpp: source file corresponding to the pre-compiled header
-
-#include "pch.h"
-
-// When you are using pre-compiled headers, this source file is necessary for compilation to succeed.
diff --git a/lib/WinRpMalloc/src/pch.h b/lib/WinRpMalloc/src/pch.h
deleted file mode 100644
index d8c2409..0000000
--- a/lib/WinRpMalloc/src/pch.h
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
-* Copyright (c) 2022 Vaughn Nugent
-*
-* Library: VNLib
-* Package: WinRpMalloc
-* File: pch.h
-*
-* pch.h is part of WinRpMalloc which is part of the larger
-* VNLib collection of libraries and utilities.
-*
-* WinRpMalloc is free software: you can redistribute it and/or modify
-* it under the terms of the GNU General Public License as published
-* by the Free Software Foundation, either version 2 of the License,
-* or (at your option) any later version.
-*
-* WinRpMalloc is distributed in the hope that it will be useful,
-* but WITHOUT ANY WARRANTY; without even the implied warranty of
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-* General Public License for more details.
-*
-* You should have received a copy of the GNU General Public License
-* along with WinRpMalloc. If not, see http://www.gnu.org/licenses/.
-*/
-
-// pch.h: This is a precompiled header file.
-// Files listed below are compiled only once, improving build performance for future builds.
-// This also affects IntelliSense performance, including code completion and many code browsing features.
-// However, files listed here are ALL re-compiled if any one of them is updated between builds.
-// Do not add files here that you will be updating frequently as this negates the performance advantage.
-
-#ifndef PCH_H
-#define PCH_H
-
-#include "framework.h"
-// add headers that you want to pre-compile here
-
-//Using firstclass heaps, define
-#define RPMALLOC_FIRST_CLASS_HEAPS 1
-
-/*
-* Enabling adaptive thread cache because I am not using thread initilaizations
-*/
-#define ENABLE_ADAPTIVE_THREAD_CACHE 1
-
-#ifdef DEBUG
-
-ENABLE_VALIDATE_ARGS 1
-ENABLE_ASSERTS 1
-ENABLE_STATISTICS 1
-
-#endif // DEBUG
-
-#include "rpmalloc.h"
-
-#endif //PCH_H
diff --git a/lib/WinRpMalloc/src/rpmalloc.c b/lib/WinRpMalloc/src/rpmalloc.c
deleted file mode 100644
index 65f6ee5..0000000
--- a/lib/WinRpMalloc/src/rpmalloc.c
+++ /dev/null
@@ -1,3616 +0,0 @@
-/* rpmalloc.c - Memory allocator - Public Domain - 2016-2020 Mattias Jansson
- *
- * This library provides a cross-platform lock free thread caching malloc implementation in C11.
- * The latest source code is always available at
- *
- * https://github.com/mjansson/rpmalloc
- *
- * This library is put in the public domain; you can redistribute it and/or modify it without any restrictions.
- *
- */
-
-
-#include "pch.h"
-#include "rpmalloc.h"
-
- ////////////
- ///
- /// Build time configurable limits
- ///
- //////
-
-#if defined(__clang__)
-#pragma clang diagnostic ignored "-Wunused-macros"
-#pragma clang diagnostic ignored "-Wunused-function"
-#if __has_warning("-Wreserved-identifier")
-#pragma clang diagnostic ignored "-Wreserved-identifier"
-#endif
-#if __has_warning("-Wstatic-in-inline")
-#pragma clang diagnostic ignored "-Wstatic-in-inline"
-#endif
-#elif defined(__GNUC__)
-#pragma GCC diagnostic ignored "-Wunused-macros"
-#pragma GCC diagnostic ignored "-Wunused-function"
-#endif
-
-#if !defined(__has_builtin)
-#define __has_builtin(b) 0
-#endif
-
-#if defined(__GNUC__) || defined(__clang__)
-
-#if __has_builtin(__builtin_memcpy_inline)
-#define _rpmalloc_memcpy_const(x, y, s) __builtin_memcpy_inline(x, y, s)
-#else
-#define _rpmalloc_memcpy_const(x, y, s) \
- do { \
- _Static_assert(__builtin_choose_expr(__builtin_constant_p(s), 1, 0), "len must be a constant integer"); \
- memcpy(x, y, s); \
- } while (0)
-#endif
-
-#if __has_builtin(__builtin_memset_inline)
-#define _rpmalloc_memset_const(x, y, s) __builtin_memset_inline(x, y, s)
-#else
-#define _rpmalloc_memset_const(x, y, s) \
- do { \
- _Static_assert(__builtin_choose_expr(__builtin_constant_p(s), 1, 0), "len must be a constant integer"); \
- memset(x, y, s); \
- } while (0)
-#endif
-#else
-#define _rpmalloc_memcpy_const(x, y, s) memcpy(x, y, s)
-#define _rpmalloc_memset_const(x, y, s) memset(x, y, s)
-#endif
-
-#if __has_builtin(__builtin_assume)
-#define rpmalloc_assume(cond) __builtin_assume(cond)
-#elif defined(__GNUC__)
-#define rpmalloc_assume(cond) \
- do { \
- if (!__builtin_expect(cond, 0)) \
- __builtin_unreachable(); \
- } while (0)
-#elif defined(_MSC_VER)
-#define rpmalloc_assume(cond) __assume(cond)
-#else
-#define rpmalloc_assume(cond) 0
-#endif
-
-#ifndef HEAP_ARRAY_SIZE
-//! Size of heap hashmap
-#define HEAP_ARRAY_SIZE 47
-#endif
-#ifndef ENABLE_THREAD_CACHE
-//! Enable per-thread cache
-#define ENABLE_THREAD_CACHE 1
-#endif
-#ifndef ENABLE_GLOBAL_CACHE
-//! Enable global cache shared between all threads, requires thread cache
-#define ENABLE_GLOBAL_CACHE 1
-#endif
-#ifndef ENABLE_VALIDATE_ARGS
-//! Enable validation of args to public entry points
-#define ENABLE_VALIDATE_ARGS 0
-#endif
-#ifndef ENABLE_STATISTICS
-//! Enable statistics collection
-#define ENABLE_STATISTICS 0
-#endif
-#ifndef ENABLE_ASSERTS
-//! Enable asserts
-#define ENABLE_ASSERTS 0
-#endif
-#ifndef ENABLE_OVERRIDE
-//! Override standard library malloc/free and new/delete entry points
-#define ENABLE_OVERRIDE 0
-#endif
-#ifndef ENABLE_PRELOAD
-//! Support preloading
-#define ENABLE_PRELOAD 0
-#endif
-#ifndef DISABLE_UNMAP
-//! Disable unmapping memory pages (also enables unlimited cache)
-#define DISABLE_UNMAP 0
-#endif
-#ifndef ENABLE_UNLIMITED_CACHE
-//! Enable unlimited global cache (no unmapping until finalization)
-#define ENABLE_UNLIMITED_CACHE 0
-#endif
-#ifndef ENABLE_ADAPTIVE_THREAD_CACHE
-//! Enable adaptive thread cache size based on use heuristics
-#define ENABLE_ADAPTIVE_THREAD_CACHE 0
-#endif
-#ifndef DEFAULT_SPAN_MAP_COUNT
-//! Default number of spans to map in call to map more virtual memory (default values yield 4MiB here)
-#define DEFAULT_SPAN_MAP_COUNT 64
-#endif
-#ifndef GLOBAL_CACHE_MULTIPLIER
-//! Multiplier for global cache
-#define GLOBAL_CACHE_MULTIPLIER 8
-#endif
-
-#if DISABLE_UNMAP && !ENABLE_GLOBAL_CACHE
-#error Must use global cache if unmap is disabled
-#endif
-
-#if DISABLE_UNMAP
-#undef ENABLE_UNLIMITED_CACHE
-#define ENABLE_UNLIMITED_CACHE 1
-#endif
-
-#if !ENABLE_GLOBAL_CACHE
-#undef ENABLE_UNLIMITED_CACHE
-#define ENABLE_UNLIMITED_CACHE 0
-#endif
-
-#if !ENABLE_THREAD_CACHE
-#undef ENABLE_ADAPTIVE_THREAD_CACHE
-#define ENABLE_ADAPTIVE_THREAD_CACHE 0
-#endif
-
-#if defined(_WIN32) || defined(__WIN32__) || defined(_WIN64)
-# define PLATFORM_WINDOWS 1
-# define PLATFORM_POSIX 0
-#else
-# define PLATFORM_WINDOWS 0
-# define PLATFORM_POSIX 1
-#endif
-
-/// Platform and arch specifics
-#if defined(_MSC_VER) && !defined(__clang__)
-# pragma warning (disable: 5105)
-# ifndef FORCEINLINE
-# define FORCEINLINE inline __forceinline
-# endif
-# define _Static_assert static_assert
-#else
-# ifndef FORCEINLINE
-# define FORCEINLINE inline __attribute__((__always_inline__))
-# endif
-#endif
-#if PLATFORM_WINDOWS
-# ifndef WIN32_LEAN_AND_MEAN
-# define WIN32_LEAN_AND_MEAN
-# endif
-# include <windows.h>
-# if ENABLE_VALIDATE_ARGS
-# include <intsafe.h>
-# endif
-#else
-# include <unistd.h>
-# include <stdio.h>
-# include <stdlib.h>
-# include <time.h>
-# if defined(__linux__) || defined(__ANDROID__)
-# include <sys/prctl.h>
-# if !defined(PR_SET_VMA)
-# define PR_SET_VMA 0x53564d41
-# define PR_SET_VMA_ANON_NAME 0
-# endif
-# endif
-# if defined(__APPLE__)
-# include <TargetConditionals.h>
-# if !TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR
-# include <mach/mach_vm.h>
-# include <mach/vm_statistics.h>
-# endif
-# include <pthread.h>
-# endif
-# if defined(__HAIKU__) || defined(__TINYC__)
-# include <pthread.h>
-# endif
-#endif
-
-#include <stdint.h>
-#include <string.h>
-#include <errno.h>
-
-#if defined(_WIN32) && (!defined(BUILD_DYNAMIC_LINK) || !BUILD_DYNAMIC_LINK)
-#include <fibersapi.h>
-static DWORD fls_key;
-#endif
-
-#if PLATFORM_POSIX
-# include <sys/mman.h>
-# include <sched.h>
-# ifdef __FreeBSD__
-# include <sys/sysctl.h>
-# define MAP_HUGETLB MAP_ALIGNED_SUPER
-# ifndef PROT_MAX
-# define PROT_MAX(f) 0
-# endif
-# else
-# define PROT_MAX(f) 0
-# endif
-# ifdef __sun
-extern int madvise(caddr_t, size_t, int);
-# endif
-# ifndef MAP_UNINITIALIZED
-# define MAP_UNINITIALIZED 0
-# endif
-#endif
-#include <errno.h>
-
-#if ENABLE_ASSERTS
-# undef NDEBUG
-# if defined(_MSC_VER) && !defined(_DEBUG)
-# define _DEBUG
-# endif
-# include <assert.h>
-#define RPMALLOC_TOSTRING_M(x) #x
-#define RPMALLOC_TOSTRING(x) RPMALLOC_TOSTRING_M(x)
-#define rpmalloc_assert(truth, message) \
- do { \
- if (!(truth)) { \
- if (_memory_config.error_callback) { \
- _memory_config.error_callback( \
- message " (" RPMALLOC_TOSTRING(truth) ") at " __FILE__ ":" RPMALLOC_TOSTRING(__LINE__)); \
- } else { \
- assert((truth) && message); \
- } \
- } \
- } while (0)
-#else
-# define rpmalloc_assert(truth, message) do {} while(0)
-#endif
-#if ENABLE_STATISTICS
-# include <stdio.h>
-#endif
-
-//////
-///
-/// Atomic access abstraction (since MSVC does not do C11 yet)
-///
-//////
-
-#if defined(_MSC_VER) && !defined(__clang__)
-
-typedef volatile long atomic32_t;
-typedef volatile long long atomic64_t;
-typedef volatile void* atomicptr_t;
-
-static FORCEINLINE int32_t atomic_load32(atomic32_t* src) { return *src; }
-static FORCEINLINE void atomic_store32(atomic32_t* dst, int32_t val) { *dst = val; }
-static FORCEINLINE int32_t atomic_incr32(atomic32_t* val) { return (int32_t)InterlockedIncrement(val); }
-static FORCEINLINE int32_t atomic_decr32(atomic32_t* val) { return (int32_t)InterlockedDecrement(val); }
-static FORCEINLINE int32_t atomic_add32(atomic32_t* val, int32_t add) { return (int32_t)InterlockedExchangeAdd(val, add) + add; }
-static FORCEINLINE int atomic_cas32_acquire(atomic32_t* dst, int32_t val, int32_t ref) { return (InterlockedCompareExchange(dst, val, ref) == ref) ? 1 : 0; }
-static FORCEINLINE void atomic_store32_release(atomic32_t* dst, int32_t val) { *dst = val; }
-static FORCEINLINE int64_t atomic_load64(atomic64_t* src) { return *src; }
-static FORCEINLINE int64_t atomic_add64(atomic64_t* val, int64_t add) { return (int64_t)InterlockedExchangeAdd64(val, add) + add; }
-static FORCEINLINE void* atomic_load_ptr(atomicptr_t* src) { return (void*)*src; }
-static FORCEINLINE void atomic_store_ptr(atomicptr_t* dst, void* val) { *dst = val; }
-static FORCEINLINE void atomic_store_ptr_release(atomicptr_t* dst, void* val) { *dst = val; }
-static FORCEINLINE void* atomic_exchange_ptr_acquire(atomicptr_t* dst, void* val) { return (void*)InterlockedExchangePointer((void* volatile*)dst, val); }
-static FORCEINLINE int atomic_cas_ptr(atomicptr_t* dst, void* val, void* ref) { return (InterlockedCompareExchangePointer((void* volatile*)dst, val, ref) == ref) ? 1 : 0; }
-
-#define EXPECTED(x) (x)
-#define UNEXPECTED(x) (x)
-
-#else
-
-#include <stdatomic.h>
-
-typedef volatile _Atomic(int32_t)atomic32_t;
-typedef volatile _Atomic(int64_t)atomic64_t;
-typedef volatile _Atomic(void*)atomicptr_t;
-
-static FORCEINLINE int32_t atomic_load32(atomic32_t* src) { return atomic_load_explicit(src, memory_order_relaxed); }
-static FORCEINLINE void atomic_store32(atomic32_t* dst, int32_t val) { atomic_store_explicit(dst, val, memory_order_relaxed); }
-static FORCEINLINE int32_t atomic_incr32(atomic32_t* val) { return atomic_fetch_add_explicit(val, 1, memory_order_relaxed) + 1; }
-static FORCEINLINE int32_t atomic_decr32(atomic32_t* val) { return atomic_fetch_add_explicit(val, -1, memory_order_relaxed) - 1; }
-static FORCEINLINE int32_t atomic_add32(atomic32_t* val, int32_t add) { return atomic_fetch_add_explicit(val, add, memory_order_relaxed) + add; }
-static FORCEINLINE int atomic_cas32_acquire(atomic32_t* dst, int32_t val, int32_t ref) { return atomic_compare_exchange_weak_explicit(dst, &ref, val, memory_order_acquire, memory_order_relaxed); }
-static FORCEINLINE void atomic_store32_release(atomic32_t* dst, int32_t val) { atomic_store_explicit(dst, val, memory_order_release); }
-static FORCEINLINE int64_t atomic_load64(atomic64_t* val) { return atomic_load_explicit(val, memory_order_relaxed); }
-static FORCEINLINE int64_t atomic_add64(atomic64_t* val, int64_t add) { return atomic_fetch_add_explicit(val, add, memory_order_relaxed) + add; }
-static FORCEINLINE void* atomic_load_ptr(atomicptr_t* src) { return atomic_load_explicit(src, memory_order_relaxed); }
-static FORCEINLINE void atomic_store_ptr(atomicptr_t* dst, void* val) { atomic_store_explicit(dst, val, memory_order_relaxed); }
-static FORCEINLINE void atomic_store_ptr_release(atomicptr_t* dst, void* val) { atomic_store_explicit(dst, val, memory_order_release); }
-static FORCEINLINE void* atomic_exchange_ptr_acquire(atomicptr_t* dst, void* val) { return atomic_exchange_explicit(dst, val, memory_order_acquire); }
-static FORCEINLINE int atomic_cas_ptr(atomicptr_t* dst, void* val, void* ref) { return atomic_compare_exchange_weak_explicit(dst, &ref, val, memory_order_relaxed, memory_order_relaxed); }
-
-#define EXPECTED(x) __builtin_expect((x), 1)
-#define UNEXPECTED(x) __builtin_expect((x), 0)
-
-#endif
-
-////////////
-///
-/// Statistics related functions (evaluate to nothing when statistics not enabled)
-///
-//////
-
-#if ENABLE_STATISTICS
-# define _rpmalloc_stat_inc(counter) atomic_incr32(counter)
-# define _rpmalloc_stat_dec(counter) atomic_decr32(counter)
-# define _rpmalloc_stat_add(counter, value) atomic_add32(counter, (int32_t)(value))
-# define _rpmalloc_stat_add64(counter, value) atomic_add64(counter, (int64_t)(value))
-# define _rpmalloc_stat_add_peak(counter, value, peak) do { int32_t _cur_count = atomic_add32(counter, (int32_t)(value)); if (_cur_count > (peak)) peak = _cur_count; } while (0)
-# define _rpmalloc_stat_sub(counter, value) atomic_add32(counter, -(int32_t)(value))
-# define _rpmalloc_stat_inc_alloc(heap, class_idx) do { \
- int32_t alloc_current = atomic_incr32(&heap->size_class_use[class_idx].alloc_current); \
- if (alloc_current > heap->size_class_use[class_idx].alloc_peak) \
- heap->size_class_use[class_idx].alloc_peak = alloc_current; \
- atomic_incr32(&heap->size_class_use[class_idx].alloc_total); \
-} while(0)
-# define _rpmalloc_stat_inc_free(heap, class_idx) do { \
- atomic_decr32(&heap->size_class_use[class_idx].alloc_current); \
- atomic_incr32(&heap->size_class_use[class_idx].free_total); \
-} while(0)
-#else
-# define _rpmalloc_stat_inc(counter) do {} while(0)
-# define _rpmalloc_stat_dec(counter) do {} while(0)
-# define _rpmalloc_stat_add(counter, value) do {} while(0)
-# define _rpmalloc_stat_add64(counter, value) do {} while(0)
-# define _rpmalloc_stat_add_peak(counter, value, peak) do {} while (0)
-# define _rpmalloc_stat_sub(counter, value) do {} while(0)
-# define _rpmalloc_stat_inc_alloc(heap, class_idx) do {} while(0)
-# define _rpmalloc_stat_inc_free(heap, class_idx) do {} while(0)
-#endif
-
-
-///
-/// Preconfigured limits and sizes
-///
-
-//! Granularity of a small allocation block (must be power of two)
-#define SMALL_GRANULARITY 16
-//! Small granularity shift count
-#define SMALL_GRANULARITY_SHIFT 4
-//! Number of small block size classes
-#define SMALL_CLASS_COUNT 65
-//! Maximum size of a small block
-#define SMALL_SIZE_LIMIT (SMALL_GRANULARITY * (SMALL_CLASS_COUNT - 1))
-//! Granularity of a medium allocation block
-#define MEDIUM_GRANULARITY 512
-//! Medium granularity shift count
-#define MEDIUM_GRANULARITY_SHIFT 9
-//! Number of medium block size classes
-#define MEDIUM_CLASS_COUNT 61
-//! Total number of small + medium size classes
-#define SIZE_CLASS_COUNT (SMALL_CLASS_COUNT + MEDIUM_CLASS_COUNT)
-//! Number of large block size classes
-#define LARGE_CLASS_COUNT 63
-//! Maximum size of a medium block
-#define MEDIUM_SIZE_LIMIT (SMALL_SIZE_LIMIT + (MEDIUM_GRANULARITY * MEDIUM_CLASS_COUNT))
-//! Maximum size of a large block
-#define LARGE_SIZE_LIMIT ((LARGE_CLASS_COUNT * _memory_span_size) - SPAN_HEADER_SIZE)
-//! Size of a span header (must be a multiple of SMALL_GRANULARITY and a power of two)
-#define SPAN_HEADER_SIZE 128
-//! Number of spans in thread cache
-#define MAX_THREAD_SPAN_CACHE 400
-//! Number of spans to transfer between thread and global cache
-#define THREAD_SPAN_CACHE_TRANSFER 64
-//! Number of spans in thread cache for large spans (must be greater than LARGE_CLASS_COUNT / 2)
-#define MAX_THREAD_SPAN_LARGE_CACHE 100
-//! Number of spans to transfer between thread and global cache for large spans
-#define THREAD_SPAN_LARGE_CACHE_TRANSFER 6
-
-_Static_assert((SMALL_GRANULARITY& (SMALL_GRANULARITY - 1)) == 0, "Small granularity must be power of two");
-_Static_assert((SPAN_HEADER_SIZE& (SPAN_HEADER_SIZE - 1)) == 0, "Span header size must be power of two");
-
-#if ENABLE_VALIDATE_ARGS
-//! Maximum allocation size to avoid integer overflow
-#undef MAX_ALLOC_SIZE
-#define MAX_ALLOC_SIZE (((size_t)-1) - _memory_span_size)
-#endif
-
-#define pointer_offset(ptr, ofs) (void*)((char*)(ptr) + (ptrdiff_t)(ofs))
-#define pointer_diff(first, second) (ptrdiff_t)((const char*)(first) - (const char*)(second))
-
-#define INVALID_POINTER ((void*)((uintptr_t)-1))
-
-#define SIZE_CLASS_LARGE SIZE_CLASS_COUNT
-#define SIZE_CLASS_HUGE ((uint32_t)-1)
-
-////////////
-///
-/// Data types
-///
-//////
-
-//! A memory heap, per thread
-typedef struct heap_t heap_t;
-//! Span of memory pages
-typedef struct span_t span_t;
-//! Span list
-typedef struct span_list_t span_list_t;
-//! Span active data
-typedef struct span_active_t span_active_t;
-//! Size class definition
-typedef struct size_class_t size_class_t;
-//! Global cache
-typedef struct global_cache_t global_cache_t;
-
-//! Flag indicating span is the first (master) span of a split superspan
-#define SPAN_FLAG_MASTER 1U
-//! Flag indicating span is a secondary (sub) span of a split superspan
-#define SPAN_FLAG_SUBSPAN 2U
-//! Flag indicating span has blocks with increased alignment
-#define SPAN_FLAG_ALIGNED_BLOCKS 4U
-//! Flag indicating an unmapped master span
-#define SPAN_FLAG_UNMAPPED_MASTER 8U
-
-#if ENABLE_ADAPTIVE_THREAD_CACHE || ENABLE_STATISTICS
-struct span_use_t {
- //! Current number of spans used (actually used, not in cache)
- atomic32_t current;
- //! High water mark of spans used
- atomic32_t high;
-#if ENABLE_STATISTICS
- //! Number of spans in deferred list
- atomic32_t spans_deferred;
- //! Number of spans transitioned to global cache
- atomic32_t spans_to_global;
- //! Number of spans transitioned from global cache
- atomic32_t spans_from_global;
- //! Number of spans transitioned to thread cache
- atomic32_t spans_to_cache;
- //! Number of spans transitioned from thread cache
- atomic32_t spans_from_cache;
- //! Number of spans transitioned to reserved state
- atomic32_t spans_to_reserved;
- //! Number of spans transitioned from reserved state
- atomic32_t spans_from_reserved;
- //! Number of raw memory map calls
- atomic32_t spans_map_calls;
-#endif
-};
-typedef struct span_use_t span_use_t;
-#endif
-
-#if ENABLE_STATISTICS
-struct size_class_use_t {
- //! Current number of allocations
- atomic32_t alloc_current;
- //! Peak number of allocations
- int32_t alloc_peak;
- //! Total number of allocations
- atomic32_t alloc_total;
- //! Total number of frees
- atomic32_t free_total;
- //! Number of spans in use
- atomic32_t spans_current;
- //! Number of spans transitioned to cache
- int32_t spans_peak;
- //! Number of spans transitioned to cache
- atomic32_t spans_to_cache;
- //! Number of spans transitioned from cache
- atomic32_t spans_from_cache;
- //! Number of spans transitioned from reserved state
- atomic32_t spans_from_reserved;
- //! Number of spans mapped
- atomic32_t spans_map_calls;
- int32_t unused;
-};
-typedef struct size_class_use_t size_class_use_t;
-#endif
-
-// A span can either represent a single span of memory pages with size declared by span_map_count configuration variable,
-// or a set of spans in a continuous region, a super span. Any reference to the term "span" usually refers to both a single
-// span or a super span. A super span can further be divided into multiple spans (or this, super spans), where the first
-// (super)span is the master and subsequent (super)spans are subspans. The master span keeps track of how many subspans
-// that are still alive and mapped in virtual memory, and once all subspans and master have been unmapped the entire
-// superspan region is released and unmapped (on Windows for example, the entire superspan range has to be released
-// in the same call to release the virtual memory range, but individual subranges can be decommitted individually
-// to reduce physical memory use).
-struct span_t {
- //! Free list
- void* free_list;
- //! Total block count of size class
- uint32_t block_count;
- //! Size class
- uint32_t size_class;
- //! Index of last block initialized in free list
- uint32_t free_list_limit;
- //! Number of used blocks remaining when in partial state
- uint32_t used_count;
- //! Deferred free list
- atomicptr_t free_list_deferred;
- //! Size of deferred free list, or list of spans when part of a cache list
- uint32_t list_size;
- //! Size of a block
- uint32_t block_size;
- //! Flags and counters
- uint32_t flags;
- //! Number of spans
- uint32_t span_count;
- //! Total span counter for master spans
- uint32_t total_spans;
- //! Offset from master span for subspans
- uint32_t offset_from_master;
- //! Remaining span counter, for master spans
- atomic32_t remaining_spans;
- //! Alignment offset
- uint32_t align_offset;
- //! Owning heap
- heap_t* heap;
- //! Next span
- span_t* next;
- //! Previous span
- span_t* prev;
-};
-_Static_assert(sizeof(span_t) <= SPAN_HEADER_SIZE, "span size mismatch");
-
-struct span_cache_t {
- size_t count;
- span_t* span[MAX_THREAD_SPAN_CACHE];
-};
-typedef struct span_cache_t span_cache_t;
-
-struct span_large_cache_t {
- size_t count;
- span_t* span[MAX_THREAD_SPAN_LARGE_CACHE];
-};
-typedef struct span_large_cache_t span_large_cache_t;
-
-struct heap_size_class_t {
- //! Free list of active span
- void* free_list;
- //! Double linked list of partially used spans with free blocks.
- // Previous span pointer in head points to tail span of list.
- span_t* partial_span;
- //! Early level cache of fully free spans
- span_t* cache;
-};
-typedef struct heap_size_class_t heap_size_class_t;
-
-// Control structure for a heap, either a thread heap or a first class heap if enabled
-struct heap_t {
- //! Owning thread ID
- uintptr_t owner_thread;
- //! Free lists for each size class
- heap_size_class_t size_class[SIZE_CLASS_COUNT];
-#if ENABLE_THREAD_CACHE
- //! Arrays of fully freed spans, single span
- span_cache_t span_cache;
-#endif
- //! List of deferred free spans (single linked list)
- atomicptr_t span_free_deferred;
- //! Number of full spans
- size_t full_span_count;
- //! Mapped but unused spans
- span_t* span_reserve;
- //! Master span for mapped but unused spans
- span_t* span_reserve_master;
- //! Number of mapped but unused spans
- uint32_t spans_reserved;
- //! Child count
- atomic32_t child_count;
- //! Next heap in id list
- heap_t* next_heap;
- //! Next heap in orphan list
- heap_t* next_orphan;
- //! Heap ID
- int32_t id;
- //! Finalization state flag
- int finalize;
- //! Master heap owning the memory pages
- heap_t* master_heap;
-#if ENABLE_THREAD_CACHE
- //! Arrays of fully freed spans, large spans with > 1 span count
- span_large_cache_t span_large_cache[LARGE_CLASS_COUNT - 1];
-#endif
-#if RPMALLOC_FIRST_CLASS_HEAPS
- //! Double linked list of fully utilized spans with free blocks for each size class.
- // Previous span pointer in head points to tail span of list.
- span_t* full_span[SIZE_CLASS_COUNT];
- //! Double linked list of large and huge spans allocated by this heap
- span_t* large_huge_span;
-#endif
-#if ENABLE_ADAPTIVE_THREAD_CACHE || ENABLE_STATISTICS
- //! Current and high water mark of spans used per span count
- span_use_t span_use[LARGE_CLASS_COUNT];
-#endif
-#if ENABLE_STATISTICS
- //! Allocation stats per size class
- size_class_use_t size_class_use[SIZE_CLASS_COUNT + 1];
- //! Number of bytes transitioned thread -> global
- atomic64_t thread_to_global;
- //! Number of bytes transitioned global -> thread
- atomic64_t global_to_thread;
-#endif
-};
-
-// Size class for defining a block size bucket
-struct size_class_t {
- //! Size of blocks in this class
- uint32_t block_size;
- //! Number of blocks in each chunk
- uint16_t block_count;
- //! Class index this class is merged with
- uint16_t class_idx;
-};
-_Static_assert(sizeof(size_class_t) == 8, "Size class size mismatch");
-
-struct global_cache_t {
- //! Cache lock
- atomic32_t lock;
- //! Cache count
- uint32_t count;
-#if ENABLE_STATISTICS
- //! Insert count
- size_t insert_count;
- //! Extract count
- size_t extract_count;
-#endif
- //! Cached spans
- span_t* span[GLOBAL_CACHE_MULTIPLIER * MAX_THREAD_SPAN_CACHE];
- //! Unlimited cache overflow
- span_t* overflow;
-};
-
-////////////
-///
-/// Global data
-///
-//////
-
-//! Default span size (64KiB)
-#define _memory_default_span_size (64 * 1024)
-#define _memory_default_span_size_shift 16
-#define _memory_default_span_mask (~((uintptr_t)(_memory_span_size - 1)))
-
-//! Initialized flag
-static int _rpmalloc_initialized;
-//! Main thread ID
-static uintptr_t _rpmalloc_main_thread_id;
-//! Configuration
-static rpmalloc_config_t _memory_config;
-//! Memory page size
-static size_t _memory_page_size;
-//! Shift to divide by page size
-static size_t _memory_page_size_shift;
-//! Granularity at which memory pages are mapped by OS
-static size_t _memory_map_granularity;
-#if RPMALLOC_CONFIGURABLE
-//! Size of a span of memory pages
-static size_t _memory_span_size;
-//! Shift to divide by span size
-static size_t _memory_span_size_shift;
-//! Mask to get to start of a memory span
-static uintptr_t _memory_span_mask;
-#else
-//! Hardwired span size
-#define _memory_span_size _memory_default_span_size
-#define _memory_span_size_shift _memory_default_span_size_shift
-#define _memory_span_mask _memory_default_span_mask
-#endif
-//! Number of spans to map in each map call
-static size_t _memory_span_map_count;
-//! Number of spans to keep reserved in each heap
-static size_t _memory_heap_reserve_count;
-//! Global size classes
-static size_class_t _memory_size_class[SIZE_CLASS_COUNT];
-//! Run-time size limit of medium blocks
-static size_t _memory_medium_size_limit;
-//! Heap ID counter
-static atomic32_t _memory_heap_id;
-//! Huge page support
-static int _memory_huge_pages;
-#if ENABLE_GLOBAL_CACHE
-//! Global span cache
-static global_cache_t _memory_span_cache[LARGE_CLASS_COUNT];
-#endif
-//! Global reserved spans
-static span_t* _memory_global_reserve;
-//! Global reserved count
-static size_t _memory_global_reserve_count;
-//! Global reserved master
-static span_t* _memory_global_reserve_master;
-//! All heaps
-static heap_t* _memory_heaps[HEAP_ARRAY_SIZE];
-//! Used to restrict access to mapping memory for huge pages
-static atomic32_t _memory_global_lock;
-//! Orphaned heaps
-static heap_t* _memory_orphan_heaps;
-#if RPMALLOC_FIRST_CLASS_HEAPS
-//! Orphaned heaps (first class heaps)
-static heap_t* _memory_first_class_orphan_heaps;
-#endif
-#if ENABLE_STATISTICS
-//! Allocations counter
-static atomic64_t _allocation_counter;
-//! Deallocations counter
-static atomic64_t _deallocation_counter;
-//! Active heap count
-static atomic32_t _memory_active_heaps;
-//! Number of currently mapped memory pages
-static atomic32_t _mapped_pages;
-//! Peak number of concurrently mapped memory pages
-static int32_t _mapped_pages_peak;
-//! Number of mapped master spans
-static atomic32_t _master_spans;
-//! Number of unmapped dangling master spans
-static atomic32_t _unmapped_master_spans;
-//! Running counter of total number of mapped memory pages since start
-static atomic32_t _mapped_total;
-//! Running counter of total number of unmapped memory pages since start
-static atomic32_t _unmapped_total;
-//! Number of currently mapped memory pages in OS calls
-static atomic32_t _mapped_pages_os;
-//! Number of currently allocated pages in huge allocations
-static atomic32_t _huge_pages_current;
-//! Peak number of currently allocated pages in huge allocations
-static int32_t _huge_pages_peak;
-#endif
-
-////////////
-///
-/// Thread local heap and ID
-///
-//////
-
-//! Current thread heap
-#if ((defined(__APPLE__) || defined(__HAIKU__)) && ENABLE_PRELOAD) || defined(__TINYC__)
-static pthread_key_t _memory_thread_heap;
-#else
-# ifdef _MSC_VER
-# define _Thread_local __declspec(thread)
-# define TLS_MODEL
-# else
-# ifndef __HAIKU__
-# define TLS_MODEL __attribute__((tls_model("initial-exec")))
-# else
-# define TLS_MODEL
-# endif
-# if !defined(__clang__) && defined(__GNUC__)
-# define _Thread_local __thread
-# endif
-# endif
-static _Thread_local heap_t* _memory_thread_heap TLS_MODEL;
-#endif
-
-static inline heap_t*
-get_thread_heap_raw(void) {
-#if (defined(__APPLE__) || defined(__HAIKU__)) && ENABLE_PRELOAD
- return pthread_getspecific(_memory_thread_heap);
-#else
- return _memory_thread_heap;
-#endif
-}
-
-//! Get the current thread heap
-static inline heap_t*
-get_thread_heap(void) {
- heap_t* heap = get_thread_heap_raw();
-#if ENABLE_PRELOAD
- if (EXPECTED(heap != 0))
- return heap;
- rpmalloc_initialize();
- return get_thread_heap_raw();
-#else
- return heap;
-#endif
-}
-
-//! Fast thread ID
-static inline uintptr_t
-get_thread_id(void) {
-#if defined(_WIN32)
- return (uintptr_t)((void*)NtCurrentTeb());
-#elif (defined(__GNUC__) || defined(__clang__)) && !defined(__CYGWIN__)
- uintptr_t tid;
-# if defined(__i386__)
- __asm__("movl %%gs:0, %0" : "=r" (tid) : : );
-# elif defined(__x86_64__)
-# if defined(__MACH__)
- __asm__("movq %%gs:0, %0" : "=r" (tid) : : );
-# else
- __asm__("movq %%fs:0, %0" : "=r" (tid) : : );
-# endif
-# elif defined(__arm__)
- __asm__ volatile ("mrc p15, 0, %0, c13, c0, 3" : "=r" (tid));
-# elif defined(__aarch64__)
-# if defined(__MACH__)
- // tpidr_el0 likely unused, always return 0 on iOS
- __asm__ volatile ("mrs %0, tpidrro_el0" : "=r" (tid));
-# else
- __asm__ volatile ("mrs %0, tpidr_el0" : "=r" (tid));
-# endif
-# else
-# error This platform needs implementation of get_thread_id()
-# endif
- return tid;
-#else
-# error This platform needs implementation of get_thread_id()
-#endif
-}
-
-//! Set the current thread heap
-static void
-set_thread_heap(heap_t* heap) {
-#if ((defined(__APPLE__) || defined(__HAIKU__)) && ENABLE_PRELOAD) || defined(__TINYC__)
- pthread_setspecific(_memory_thread_heap, heap);
-#else
- _memory_thread_heap = heap;
-#endif
- if (heap)
- heap->owner_thread = get_thread_id();
-}
-
-//! Set main thread ID
-extern void
-rpmalloc_set_main_thread(void);
-
-void
-rpmalloc_set_main_thread(void) {
- _rpmalloc_main_thread_id = get_thread_id();
-}
-
-static void
-_rpmalloc_spin(void) {
-#if defined(_MSC_VER)
- _mm_pause();
-#elif defined(__x86_64__) || defined(__i386__)
- __asm__ volatile("pause" ::: "memory");
-#elif defined(__aarch64__) || (defined(__arm__) && __ARM_ARCH >= 7)
- __asm__ volatile("yield" ::: "memory");
-#elif defined(__powerpc__) || defined(__powerpc64__)
- // No idea if ever been compiled in such archs but ... as precaution
- __asm__ volatile("or 27,27,27");
-#elif defined(__sparc__)
- __asm__ volatile("rd %ccr, %g0 \n\trd %ccr, %g0 \n\trd %ccr, %g0");
-#else
- struct timespec ts = { 0 };
- nanosleep(&ts, 0);
-#endif
-}
-
-#if defined(_WIN32) && (!defined(BUILD_DYNAMIC_LINK) || !BUILD_DYNAMIC_LINK)
-static void NTAPI
-_rpmalloc_thread_destructor(void* value) {
-#if ENABLE_OVERRIDE
- // If this is called on main thread it means rpmalloc_finalize
- // has not been called and shutdown is forced (through _exit) or unclean
- if (get_thread_id() == _rpmalloc_main_thread_id)
- return;
-#endif
- if (value)
- rpmalloc_thread_finalize(1);
-}
-#endif
-
-
-////////////
-///
-/// Low level memory map/unmap
-///
-//////
-
-static void
-_rpmalloc_set_name(void* address, size_t size) {
-#if defined(__linux__) || defined(__ANDROID__)
- const char* name = _memory_huge_pages ? _memory_config.huge_page_name : _memory_config.page_name;
- if (address == MAP_FAILED || !name)
- return;
- // If the kernel does not support CONFIG_ANON_VMA_NAME or if the call fails
- // (e.g. invalid name) it is a no-op basically.
- (void)prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, (uintptr_t)address, size, (uintptr_t)name);
-#else
- (void)sizeof(size);
- (void)sizeof(address);
-#endif
-}
-
-
-//! Map more virtual memory
-// size is number of bytes to map
-// offset receives the offset in bytes from start of mapped region
-// returns address to start of mapped region to use
-static void*
-_rpmalloc_mmap(size_t size, size_t* offset) {
- rpmalloc_assert(!(size % _memory_page_size), "Invalid mmap size");
- rpmalloc_assert(size >= _memory_page_size, "Invalid mmap size");
- void* address = _memory_config.memory_map(size, offset);
- if (EXPECTED(address != 0)) {
- _rpmalloc_stat_add_peak(&_mapped_pages, (size >> _memory_page_size_shift), _mapped_pages_peak);
- _rpmalloc_stat_add(&_mapped_total, (size >> _memory_page_size_shift));
- }
- return address;
-}
-
-//! Unmap virtual memory
-// address is the memory address to unmap, as returned from _memory_map
-// size is the number of bytes to unmap, which might be less than full region for a partial unmap
-// offset is the offset in bytes to the actual mapped region, as set by _memory_map
-// release is set to 0 for partial unmap, or size of entire range for a full unmap
-static void
-_rpmalloc_unmap(void* address, size_t size, size_t offset, size_t release) {
- rpmalloc_assert(!release || (release >= size), "Invalid unmap size");
- rpmalloc_assert(!release || (release >= _memory_page_size), "Invalid unmap size");
- if (release) {
- rpmalloc_assert(!(release % _memory_page_size), "Invalid unmap size");
- _rpmalloc_stat_sub(&_mapped_pages, (release >> _memory_page_size_shift));
- _rpmalloc_stat_add(&_unmapped_total, (release >> _memory_page_size_shift));
- }
- _memory_config.memory_unmap(address, size, offset, release);
-}
-
-//! Default implementation to map new pages to virtual memory
-static void*
-_rpmalloc_mmap_os(size_t size, size_t* offset) {
- //Either size is a heap (a single page) or a (multiple) span - we only need to align spans, and only if larger than map granularity
- size_t padding = ((size >= _memory_span_size) && (_memory_span_size > _memory_map_granularity)) ? _memory_span_size : 0;
- rpmalloc_assert(size >= _memory_page_size, "Invalid mmap size");
-#if PLATFORM_WINDOWS
- //Ok to MEM_COMMIT - according to MSDN, "actual physical pages are not allocated unless/until the virtual addresses are actually accessed"
- void* ptr = VirtualAlloc(0, size + padding, (_memory_huge_pages ? MEM_LARGE_PAGES : 0) | MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
- if (!ptr) {
- if (_memory_config.map_fail_callback) {
- if (_memory_config.map_fail_callback(size + padding))
- return _rpmalloc_mmap_os(size, offset);
- }
- else {
- rpmalloc_assert(ptr, "Failed to map virtual memory block");
- }
- return 0;
- }
-#else
- int flags = MAP_PRIVATE | MAP_ANONYMOUS | MAP_UNINITIALIZED;
-# if defined(__APPLE__) && !TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR
- int fd = (int)VM_MAKE_TAG(240U);
- if (_memory_huge_pages)
- fd |= VM_FLAGS_SUPERPAGE_SIZE_2MB;
- void* ptr = mmap(0, size + padding, PROT_READ | PROT_WRITE, flags, fd, 0);
-# elif defined(MAP_HUGETLB)
- void* ptr = mmap(0, size + padding, PROT_READ | PROT_WRITE | PROT_MAX(PROT_READ | PROT_WRITE), (_memory_huge_pages ? MAP_HUGETLB : 0) | flags, -1, 0);
-# if defined(MADV_HUGEPAGE)
- // In some configurations, huge pages allocations might fail thus
- // we fallback to normal allocations and promote the region as transparent huge page
- if ((ptr == MAP_FAILED || !ptr) && _memory_huge_pages) {
- ptr = mmap(0, size + padding, PROT_READ | PROT_WRITE, flags, -1, 0);
- if (ptr && ptr != MAP_FAILED) {
- int prm = madvise(ptr, size + padding, MADV_HUGEPAGE);
- (void)prm;
- rpmalloc_assert((prm == 0), "Failed to promote the page to THP");
- }
- }
-# endif
- _rpmalloc_set_name(ptr, size + padding);
-# elif defined(MAP_ALIGNED)
- const size_t align = (sizeof(size_t) * 8) - (size_t)(__builtin_clzl(size - 1));
- void* ptr = mmap(0, size + padding, PROT_READ | PROT_WRITE, (_memory_huge_pages ? MAP_ALIGNED(align) : 0) | flags, -1, 0);
-# elif defined(MAP_ALIGN)
- caddr_t base = (_memory_huge_pages ? (caddr_t)(4 << 20) : 0);
- void* ptr = mmap(base, size + padding, PROT_READ | PROT_WRITE, (_memory_huge_pages ? MAP_ALIGN : 0) | flags, -1, 0);
-# else
- void* ptr = mmap(0, size + padding, PROT_READ | PROT_WRITE, flags, -1, 0);
-# endif
- if ((ptr == MAP_FAILED) || !ptr) {
- if (_memory_config.map_fail_callback) {
- if (_memory_config.map_fail_callback(size + padding))
- return _rpmalloc_mmap_os(size, offset);
- }
- else if (errno != ENOMEM) {
- rpmalloc_assert((ptr != MAP_FAILED) && ptr, "Failed to map virtual memory block");
- }
- return 0;
- }
-#endif
- _rpmalloc_stat_add(&_mapped_pages_os, (int32_t)((size + padding) >> _memory_page_size_shift));
- if (padding) {
- size_t final_padding = padding - ((uintptr_t)ptr & ~_memory_span_mask);
- rpmalloc_assert(final_padding <= _memory_span_size, "Internal failure in padding");
- rpmalloc_assert(final_padding <= padding, "Internal failure in padding");
- rpmalloc_assert(!(final_padding % 8), "Internal failure in padding");
- ptr = pointer_offset(ptr, final_padding);
- *offset = final_padding >> 3;
- }
- rpmalloc_assert((size < _memory_span_size) || !((uintptr_t)ptr & ~_memory_span_mask), "Internal failure in padding");
- return ptr;
-}
-
-//! Default implementation to unmap pages from virtual memory
-static void
-_rpmalloc_unmap_os(void* address, size_t size, size_t offset, size_t release) {
- rpmalloc_assert(release || (offset == 0), "Invalid unmap size");
- rpmalloc_assert(!release || (release >= _memory_page_size), "Invalid unmap size");
- rpmalloc_assert(size >= _memory_page_size, "Invalid unmap size");
- if (release && offset) {
- offset <<= 3;
- address = pointer_offset(address, -(int32_t)offset);
- if ((release >= _memory_span_size) && (_memory_span_size > _memory_map_granularity)) {
- //Padding is always one span size
- release += _memory_span_size;
- }
- }
-#if !DISABLE_UNMAP
-#if PLATFORM_WINDOWS
- if (!VirtualFree(address, release ? 0 : size, release ? MEM_RELEASE : MEM_DECOMMIT)) {
- rpmalloc_assert(0, "Failed to unmap virtual memory block");
- }
-#else
- if (release) {
- if (munmap(address, release)) {
- rpmalloc_assert(0, "Failed to unmap virtual memory block");
- }
- }
- else {
-#if defined(MADV_FREE_REUSABLE)
- int ret;
- while ((ret = madvise(address, size, MADV_FREE_REUSABLE)) == -1 && (errno == EAGAIN))
- errno = 0;
- if ((ret == -1) && (errno != 0)) {
-#elif defined(MADV_DONTNEED)
- if (madvise(address, size, MADV_DONTNEED)) {
-#elif defined(MADV_PAGEOUT)
- if (madvise(address, size, MADV_PAGEOUT)) {
-#elif defined(MADV_FREE)
- if (madvise(address, size, MADV_FREE)) {
-#else
- if (posix_madvise(address, size, POSIX_MADV_DONTNEED)) {
-#endif
- rpmalloc_assert(0, "Failed to madvise virtual memory block as free");
- }
- }
-#endif
-#endif
- if (release)
- _rpmalloc_stat_sub(&_mapped_pages_os, release >> _memory_page_size_shift);
- }
-
-static void
-_rpmalloc_span_mark_as_subspan_unless_master(span_t * master, span_t * subspan, size_t span_count);
-
-//! Use global reserved spans to fulfill a memory map request (reserve size must be checked by caller)
-static span_t*
-_rpmalloc_global_get_reserved_spans(size_t span_count) {
- span_t* span = _memory_global_reserve;
- _rpmalloc_span_mark_as_subspan_unless_master(_memory_global_reserve_master, span, span_count);
- _memory_global_reserve_count -= span_count;
- if (_memory_global_reserve_count)
- _memory_global_reserve = (span_t*)pointer_offset(span, span_count << _memory_span_size_shift);
- else
- _memory_global_reserve = 0;
- return span;
-}
-
-//! Store the given spans as global reserve (must only be called from within new heap allocation, not thread safe)
-static void
-_rpmalloc_global_set_reserved_spans(span_t * master, span_t * reserve, size_t reserve_span_count) {
- _memory_global_reserve_master = master;
- _memory_global_reserve_count = reserve_span_count;
- _memory_global_reserve = reserve;
-}
-
-
-////////////
-///
-/// Span linked list management
-///
-//////
-
-//! Add a span to double linked list at the head
-static void
-_rpmalloc_span_double_link_list_add(span_t * *head, span_t * span) {
- if (*head)
- (*head)->prev = span;
- span->next = *head;
- *head = span;
-}
-
-//! Pop head span from double linked list
-static void
-_rpmalloc_span_double_link_list_pop_head(span_t * *head, span_t * span) {
- rpmalloc_assert(*head == span, "Linked list corrupted");
- span = *head;
- *head = span->next;
-}
-
-//! Remove a span from double linked list
-static void
-_rpmalloc_span_double_link_list_remove(span_t * *head, span_t * span) {
- rpmalloc_assert(*head, "Linked list corrupted");
- if (*head == span) {
- *head = span->next;
- }
- else {
- span_t* next_span = span->next;
- span_t* prev_span = span->prev;
- prev_span->next = next_span;
- if (EXPECTED(next_span != 0))
- next_span->prev = prev_span;
- }
-}
-
-
-////////////
-///
-/// Span control
-///
-//////
-
-static void
-_rpmalloc_heap_cache_insert(heap_t * heap, span_t * span);
-
-static void
-_rpmalloc_heap_finalize(heap_t * heap);
-
-static void
-_rpmalloc_heap_set_reserved_spans(heap_t * heap, span_t * master, span_t * reserve, size_t reserve_span_count);
-
-//! Declare the span to be a subspan and store distance from master span and span count
-static void
-_rpmalloc_span_mark_as_subspan_unless_master(span_t * master, span_t * subspan, size_t span_count) {
- rpmalloc_assert((subspan != master) || (subspan->flags & SPAN_FLAG_MASTER), "Span master pointer and/or flag mismatch");
- if (subspan != master) {
- subspan->flags = SPAN_FLAG_SUBSPAN;
- subspan->offset_from_master = (uint32_t)((uintptr_t)pointer_diff(subspan, master) >> _memory_span_size_shift);
- subspan->align_offset = 0;
- }
- subspan->span_count = (uint32_t)span_count;
-}
-
-//! Use reserved spans to fulfill a memory map request (reserve size must be checked by caller)
-static span_t*
-_rpmalloc_span_map_from_reserve(heap_t * heap, size_t span_count) {
- //Update the heap span reserve
- span_t* span = heap->span_reserve;
- heap->span_reserve = (span_t*)pointer_offset(span, span_count * _memory_span_size);
- heap->spans_reserved -= (uint32_t)span_count;
-
- _rpmalloc_span_mark_as_subspan_unless_master(heap->span_reserve_master, span, span_count);
- if (span_count <= LARGE_CLASS_COUNT)
- _rpmalloc_stat_inc(&heap->span_use[span_count - 1].spans_from_reserved);
-
- return span;
-}
-
-//! Get the aligned number of spans to map in based on wanted count, configured mapping granularity and the page size
-static size_t
-_rpmalloc_span_align_count(size_t span_count) {
- size_t request_count = (span_count > _memory_span_map_count) ? span_count : _memory_span_map_count;
- if ((_memory_page_size > _memory_span_size) && ((request_count * _memory_span_size) % _memory_page_size))
- request_count += _memory_span_map_count - (request_count % _memory_span_map_count);
- return request_count;
-}
-
-//! Setup a newly mapped span
-static void
-_rpmalloc_span_initialize(span_t * span, size_t total_span_count, size_t span_count, size_t align_offset) {
- span->total_spans = (uint32_t)total_span_count;
- span->span_count = (uint32_t)span_count;
- span->align_offset = (uint32_t)align_offset;
- span->flags = SPAN_FLAG_MASTER;
- atomic_store32(&span->remaining_spans, (int32_t)total_span_count);
-}
-
-static void
-_rpmalloc_span_unmap(span_t * span);
-
-//! Map an aligned set of spans, taking configured mapping granularity and the page size into account
-static span_t*
-_rpmalloc_span_map_aligned_count(heap_t * heap, size_t span_count) {
- //If we already have some, but not enough, reserved spans, release those to heap cache and map a new
- //full set of spans. Otherwise we would waste memory if page size > span size (huge pages)
- size_t aligned_span_count = _rpmalloc_span_align_count(span_count);
- size_t align_offset = 0;
- span_t* span = (span_t*)_rpmalloc_mmap(aligned_span_count * _memory_span_size, &align_offset);
- if (!span)
- return 0;
- _rpmalloc_span_initialize(span, aligned_span_count, span_count, align_offset);
- _rpmalloc_stat_inc(&_master_spans);
- if (span_count <= LARGE_CLASS_COUNT)
- _rpmalloc_stat_inc(&heap->span_use[span_count - 1].spans_map_calls);
- if (aligned_span_count > span_count) {
- span_t* reserved_spans = (span_t*)pointer_offset(span, span_count * _memory_span_size);
- size_t reserved_count = aligned_span_count - span_count;
- if (heap->spans_reserved) {
- _rpmalloc_span_mark_as_subspan_unless_master(heap->span_reserve_master, heap->span_reserve, heap->spans_reserved);
- _rpmalloc_heap_cache_insert(heap, heap->span_reserve);
- }
- if (reserved_count > _memory_heap_reserve_count) {
- // If huge pages or eager spam map count, the global reserve spin lock is held by caller, _rpmalloc_span_map
- rpmalloc_assert(atomic_load32(&_memory_global_lock) == 1, "Global spin lock not held as expected");
- size_t remain_count = reserved_count - _memory_heap_reserve_count;
- reserved_count = _memory_heap_reserve_count;
- span_t* remain_span = (span_t*)pointer_offset(reserved_spans, reserved_count * _memory_span_size);
- if (_memory_global_reserve) {
- _rpmalloc_span_mark_as_subspan_unless_master(_memory_global_reserve_master, _memory_global_reserve, _memory_global_reserve_count);
- _rpmalloc_span_unmap(_memory_global_reserve);
- }
- _rpmalloc_global_set_reserved_spans(span, remain_span, remain_count);
- }
- _rpmalloc_heap_set_reserved_spans(heap, span, reserved_spans, reserved_count);
- }
- return span;
-}
-
-//! Map in memory pages for the given number of spans (or use previously reserved pages)
-static span_t*
-_rpmalloc_span_map(heap_t * heap, size_t span_count) {
- if (span_count <= heap->spans_reserved)
- return _rpmalloc_span_map_from_reserve(heap, span_count);
- span_t* span = 0;
- int use_global_reserve = (_memory_page_size > _memory_span_size) || (_memory_span_map_count > _memory_heap_reserve_count);
- if (use_global_reserve) {
- // If huge pages, make sure only one thread maps more memory to avoid bloat
- while (!atomic_cas32_acquire(&_memory_global_lock, 1, 0))
- _rpmalloc_spin();
- if (_memory_global_reserve_count >= span_count) {
- size_t reserve_count = (!heap->spans_reserved ? _memory_heap_reserve_count : span_count);
- if (_memory_global_reserve_count < reserve_count)
- reserve_count = _memory_global_reserve_count;
- span = _rpmalloc_global_get_reserved_spans(reserve_count);
- if (span) {
- if (reserve_count > span_count) {
- span_t* reserved_span = (span_t*)pointer_offset(span, span_count << _memory_span_size_shift);
- _rpmalloc_heap_set_reserved_spans(heap, _memory_global_reserve_master, reserved_span, reserve_count - span_count);
- }
- // Already marked as subspan in _rpmalloc_global_get_reserved_spans
- span->span_count = (uint32_t)span_count;
- }
- }
- }
- if (!span)
- span = _rpmalloc_span_map_aligned_count(heap, span_count);
- if (use_global_reserve)
- atomic_store32_release(&_memory_global_lock, 0);
- return span;
-}
-
-//! Unmap memory pages for the given number of spans (or mark as unused if no partial unmappings)
-static void
-_rpmalloc_span_unmap(span_t * span) {
- rpmalloc_assert((span->flags & SPAN_FLAG_MASTER) || (span->flags & SPAN_FLAG_SUBSPAN), "Span flag corrupted");
- rpmalloc_assert(!(span->flags & SPAN_FLAG_MASTER) || !(span->flags & SPAN_FLAG_SUBSPAN), "Span flag corrupted");
-
- int is_master = !!(span->flags & SPAN_FLAG_MASTER);
- span_t* master = is_master ? span : ((span_t*)pointer_offset(span, -(intptr_t)((uintptr_t)span->offset_from_master * _memory_span_size)));
- rpmalloc_assert(is_master || (span->flags & SPAN_FLAG_SUBSPAN), "Span flag corrupted");
- rpmalloc_assert(master->flags & SPAN_FLAG_MASTER, "Span flag corrupted");
-
- size_t span_count = span->span_count;
- if (!is_master) {
- //Directly unmap subspans (unless huge pages, in which case we defer and unmap entire page range with master)
- rpmalloc_assert(span->align_offset == 0, "Span align offset corrupted");
- if (_memory_span_size >= _memory_page_size)
- _rpmalloc_unmap(span, span_count * _memory_span_size, 0, 0);
- }
- else {
- //Special double flag to denote an unmapped master
- //It must be kept in memory since span header must be used
- span->flags |= SPAN_FLAG_MASTER | SPAN_FLAG_SUBSPAN | SPAN_FLAG_UNMAPPED_MASTER;
- _rpmalloc_stat_add(&_unmapped_master_spans, 1);
- }
-
- if (atomic_add32(&master->remaining_spans, -(int32_t)span_count) <= 0) {
- //Everything unmapped, unmap the master span with release flag to unmap the entire range of the super span
- rpmalloc_assert(!!(master->flags & SPAN_FLAG_MASTER) && !!(master->flags & SPAN_FLAG_SUBSPAN), "Span flag corrupted");
- size_t unmap_count = master->span_count;
- if (_memory_span_size < _memory_page_size)
- unmap_count = master->total_spans;
- _rpmalloc_stat_sub(&_master_spans, 1);
- _rpmalloc_stat_sub(&_unmapped_master_spans, 1);
- _rpmalloc_unmap(master, unmap_count * _memory_span_size, master->align_offset, (size_t)master->total_spans * _memory_span_size);
- }
-}
-
-//! Move the span (used for small or medium allocations) to the heap thread cache
-static void
-_rpmalloc_span_release_to_cache(heap_t * heap, span_t * span) {
- rpmalloc_assert(heap == span->heap, "Span heap pointer corrupted");
- rpmalloc_assert(span->size_class < SIZE_CLASS_COUNT, "Invalid span size class");
- rpmalloc_assert(span->span_count == 1, "Invalid span count");
-#if ENABLE_ADAPTIVE_THREAD_CACHE || ENABLE_STATISTICS
- atomic_decr32(&heap->span_use[0].current);
-#endif
- _rpmalloc_stat_dec(&heap->size_class_use[span->size_class].spans_current);
- if (!heap->finalize) {
- _rpmalloc_stat_inc(&heap->span_use[0].spans_to_cache);
- _rpmalloc_stat_inc(&heap->size_class_use[span->size_class].spans_to_cache);
- if (heap->size_class[span->size_class].cache)
- _rpmalloc_heap_cache_insert(heap, heap->size_class[span->size_class].cache);
- heap->size_class[span->size_class].cache = span;
- }
- else {
- _rpmalloc_span_unmap(span);
- }
-}
-
-//! Initialize a (partial) free list up to next system memory page, while reserving the first block
-//! as allocated, returning number of blocks in list
-static uint32_t
-free_list_partial_init(void** list, void** first_block, void* page_start, void* block_start, uint32_t block_count, uint32_t block_size) {
- rpmalloc_assert(block_count, "Internal failure");
- *first_block = block_start;
- if (block_count > 1) {
- void* free_block = pointer_offset(block_start, block_size);
- void* block_end = pointer_offset(block_start, (size_t)block_size * block_count);
- //If block size is less than half a memory page, bound init to next memory page boundary
- if (block_size < (_memory_page_size >> 1)) {
- void* page_end = pointer_offset(page_start, _memory_page_size);
- if (page_end < block_end)
- block_end = page_end;
- }
- *list = free_block;
- block_count = 2;
- void* next_block = pointer_offset(free_block, block_size);
- while (next_block < block_end) {
- *((void**)free_block) = next_block;
- free_block = next_block;
- ++block_count;
- next_block = pointer_offset(next_block, block_size);
- }
- *((void**)free_block) = 0;
- }
- else {
- *list = 0;
- }
- return block_count;
-}
-
-//! Initialize an unused span (from cache or mapped) to be new active span, putting the initial free list in heap class free list
-static void*
-_rpmalloc_span_initialize_new(heap_t * heap, heap_size_class_t * heap_size_class, span_t * span, uint32_t class_idx) {
- rpmalloc_assert(span->span_count == 1, "Internal failure");
- size_class_t* size_class = _memory_size_class + class_idx;
- span->size_class = class_idx;
- span->heap = heap;
- span->flags &= ~SPAN_FLAG_ALIGNED_BLOCKS;
- span->block_size = size_class->block_size;
- span->block_count = size_class->block_count;
- span->free_list = 0;
- span->list_size = 0;
- atomic_store_ptr_release(&span->free_list_deferred, 0);
-
- //Setup free list. Only initialize one system page worth of free blocks in list
- void* block;
- span->free_list_limit = free_list_partial_init(&heap_size_class->free_list, &block,
- span, pointer_offset(span, SPAN_HEADER_SIZE), size_class->block_count, size_class->block_size);
- //Link span as partial if there remains blocks to be initialized as free list, or full if fully initialized
- if (span->free_list_limit < span->block_count) {
- _rpmalloc_span_double_link_list_add(&heap_size_class->partial_span, span);
- span->used_count = span->free_list_limit;
- }
- else {
-#if RPMALLOC_FIRST_CLASS_HEAPS
- _rpmalloc_span_double_link_list_add(&heap->full_span[class_idx], span);
-#endif
- ++heap->full_span_count;
- span->used_count = span->block_count;
- }
- return block;
-}
-
-static void
-_rpmalloc_span_extract_free_list_deferred(span_t * span) {
- // We need acquire semantics on the CAS operation since we are interested in the list size
- // Refer to _rpmalloc_deallocate_defer_small_or_medium for further comments on this dependency
- do {
- span->free_list = atomic_exchange_ptr_acquire(&span->free_list_deferred, INVALID_POINTER);
- } while (span->free_list == INVALID_POINTER);
- span->used_count -= span->list_size;
- span->list_size = 0;
- atomic_store_ptr_release(&span->free_list_deferred, 0);
-}
-
-static int
-_rpmalloc_span_is_fully_utilized(span_t * span) {
- rpmalloc_assert(span->free_list_limit <= span->block_count, "Span free list corrupted");
- return !span->free_list && (span->free_list_limit >= span->block_count);
-}
-
-static int
-_rpmalloc_span_finalize(heap_t * heap, size_t iclass, span_t * span, span_t * *list_head) {
- void* free_list = heap->size_class[iclass].free_list;
- span_t* class_span = (span_t*)((uintptr_t)free_list & _memory_span_mask);
- if (span == class_span) {
- // Adopt the heap class free list back into the span free list
- void* block = span->free_list;
- void* last_block = 0;
- while (block) {
- last_block = block;
- block = *((void**)block);
- }
- uint32_t free_count = 0;
- block = free_list;
- while (block) {
- ++free_count;
- block = *((void**)block);
- }
- if (last_block) {
- *((void**)last_block) = free_list;
- }
- else {
- span->free_list = free_list;
- }
- heap->size_class[iclass].free_list = 0;
- span->used_count -= free_count;
- }
- //If this assert triggers you have memory leaks
- rpmalloc_assert(span->list_size == span->used_count, "Memory leak detected");
- if (span->list_size == span->used_count) {
- _rpmalloc_stat_dec(&heap->span_use[0].current);
- _rpmalloc_stat_dec(&heap->size_class_use[iclass].spans_current);
- // This function only used for spans in double linked lists
- if (list_head)
- _rpmalloc_span_double_link_list_remove(list_head, span);
- _rpmalloc_span_unmap(span);
- return 1;
- }
- return 0;
-}
-
-
-////////////
-///
-/// Global cache
-///
-//////
-
-#if ENABLE_GLOBAL_CACHE
-
-//! Finalize a global cache
-static void
-_rpmalloc_global_cache_finalize(global_cache_t * cache) {
- while (!atomic_cas32_acquire(&cache->lock, 1, 0))
- _rpmalloc_spin();
-
- for (size_t ispan = 0; ispan < cache->count; ++ispan)
- _rpmalloc_span_unmap(cache->span[ispan]);
- cache->count = 0;
-
- while (cache->overflow) {
- span_t* span = cache->overflow;
- cache->overflow = span->next;
- _rpmalloc_span_unmap(span);
- }
-
- atomic_store32_release(&cache->lock, 0);
-}
-
-static void
-_rpmalloc_global_cache_insert_spans(span_t * *span, size_t span_count, size_t count) {
- const size_t cache_limit = (span_count == 1) ?
- GLOBAL_CACHE_MULTIPLIER * MAX_THREAD_SPAN_CACHE :
- GLOBAL_CACHE_MULTIPLIER * (MAX_THREAD_SPAN_LARGE_CACHE - (span_count >> 1));
-
- global_cache_t* cache = &_memory_span_cache[span_count - 1];
-
- size_t insert_count = count;
- while (!atomic_cas32_acquire(&cache->lock, 1, 0))
- _rpmalloc_spin();
-
-#if ENABLE_STATISTICS
- cache->insert_count += count;
-#endif
- if ((cache->count + insert_count) > cache_limit)
- insert_count = cache_limit - cache->count;
-
- memcpy(cache->span + cache->count, span, sizeof(span_t*) * insert_count);
- cache->count += (uint32_t)insert_count;
-
-#if ENABLE_UNLIMITED_CACHE
- while (insert_count < count) {
-#else
- // Enable unlimited cache if huge pages, or we will leak since it is unlikely that an entire huge page
- // will be unmapped, and we're unable to partially decommit a huge page
- while ((_memory_page_size > _memory_span_size) && (insert_count < count)) {
-#endif
- span_t* current_span = span[insert_count++];
- current_span->next = cache->overflow;
- cache->overflow = current_span;
- }
- atomic_store32_release(&cache->lock, 0);
-
- span_t* keep = 0;
- for (size_t ispan = insert_count; ispan < count; ++ispan) {
- span_t* current_span = span[ispan];
- // Keep master spans that has remaining subspans to avoid dangling them
- if ((current_span->flags & SPAN_FLAG_MASTER) &&
- (atomic_load32(&current_span->remaining_spans) > (int32_t)current_span->span_count)) {
- current_span->next = keep;
- keep = current_span;
- }
- else {
- _rpmalloc_span_unmap(current_span);
- }
- }
-
- if (keep) {
- while (!atomic_cas32_acquire(&cache->lock, 1, 0))
- _rpmalloc_spin();
-
- size_t islot = 0;
- while (keep) {
- for (; islot < cache->count; ++islot) {
- span_t* current_span = cache->span[islot];
- if (!(current_span->flags & SPAN_FLAG_MASTER) || ((current_span->flags & SPAN_FLAG_MASTER) &&
- (atomic_load32(&current_span->remaining_spans) <= (int32_t)current_span->span_count))) {
- _rpmalloc_span_unmap(current_span);
- cache->span[islot] = keep;
- break;
- }
- }
- if (islot == cache->count)
- break;
- keep = keep->next;
- }
-
- if (keep) {
- span_t* tail = keep;
- while (tail->next)
- tail = tail->next;
- tail->next = cache->overflow;
- cache->overflow = keep;
- }
-
- atomic_store32_release(&cache->lock, 0);
- }
- }
-
-static size_t
-_rpmalloc_global_cache_extract_spans(span_t * *span, size_t span_count, size_t count) {
- global_cache_t* cache = &_memory_span_cache[span_count - 1];
-
- size_t extract_count = 0;
- while (!atomic_cas32_acquire(&cache->lock, 1, 0))
- _rpmalloc_spin();
-
-#if ENABLE_STATISTICS
- cache->extract_count += count;
-#endif
- size_t want = count - extract_count;
- if (want > cache->count)
- want = cache->count;
-
- memcpy(span + extract_count, cache->span + (cache->count - want), sizeof(span_t*) * want);
- cache->count -= (uint32_t)want;
- extract_count += want;
-
- while ((extract_count < count) && cache->overflow) {
- span_t* current_span = cache->overflow;
- span[extract_count++] = current_span;
- cache->overflow = current_span->next;
- }
-
-#if ENABLE_ASSERTS
- for (size_t ispan = 0; ispan < extract_count; ++ispan) {
- rpmalloc_assert(span[ispan]->span_count == span_count, "Global cache span count mismatch");
- }
-#endif
-
- atomic_store32_release(&cache->lock, 0);
-
- return extract_count;
-}
-
-#endif
-
-////////////
-///
-/// Heap control
-///
-//////
-
-static void _rpmalloc_deallocate_huge(span_t*);
-
-//! Store the given spans as reserve in the given heap
-static void
-_rpmalloc_heap_set_reserved_spans(heap_t * heap, span_t * master, span_t * reserve, size_t reserve_span_count) {
- heap->span_reserve_master = master;
- heap->span_reserve = reserve;
- heap->spans_reserved = (uint32_t)reserve_span_count;
-}
-
-//! Adopt the deferred span cache list, optionally extracting the first single span for immediate re-use
-static void
-_rpmalloc_heap_cache_adopt_deferred(heap_t * heap, span_t * *single_span) {
- span_t* span = (span_t*)((void*)atomic_exchange_ptr_acquire(&heap->span_free_deferred, 0));
- while (span) {
- span_t* next_span = (span_t*)span->free_list;
- rpmalloc_assert(span->heap == heap, "Span heap pointer corrupted");
- if (EXPECTED(span->size_class < SIZE_CLASS_COUNT)) {
- rpmalloc_assert(heap->full_span_count, "Heap span counter corrupted");
- --heap->full_span_count;
- _rpmalloc_stat_dec(&heap->span_use[0].spans_deferred);
-#if RPMALLOC_FIRST_CLASS_HEAPS
- _rpmalloc_span_double_link_list_remove(&heap->full_span[span->size_class], span);
-#endif
- _rpmalloc_stat_dec(&heap->span_use[0].current);
- _rpmalloc_stat_dec(&heap->size_class_use[span->size_class].spans_current);
- if (single_span && !*single_span)
- *single_span = span;
- else
- _rpmalloc_heap_cache_insert(heap, span);
- }
- else {
- if (span->size_class == SIZE_CLASS_HUGE) {
- _rpmalloc_deallocate_huge(span);
- }
- else {
- rpmalloc_assert(span->size_class == SIZE_CLASS_LARGE, "Span size class invalid");
- rpmalloc_assert(heap->full_span_count, "Heap span counter corrupted");
- --heap->full_span_count;
-#if RPMALLOC_FIRST_CLASS_HEAPS
- _rpmalloc_span_double_link_list_remove(&heap->large_huge_span, span);
-#endif
- uint32_t idx = span->span_count - 1;
- _rpmalloc_stat_dec(&heap->span_use[idx].spans_deferred);
- _rpmalloc_stat_dec(&heap->span_use[idx].current);
- if (!idx && single_span && !*single_span)
- *single_span = span;
- else
- _rpmalloc_heap_cache_insert(heap, span);
- }
- }
- span = next_span;
- }
-}
-
-static void
-_rpmalloc_heap_unmap(heap_t * heap) {
- if (!heap->master_heap) {
- if ((heap->finalize > 1) && !atomic_load32(&heap->child_count)) {
- span_t* span = (span_t*)((uintptr_t)heap & _memory_span_mask);
- _rpmalloc_span_unmap(span);
- }
- }
- else {
- if (atomic_decr32(&heap->master_heap->child_count) == 0) {
- _rpmalloc_heap_unmap(heap->master_heap);
- }
- }
-}
-
-static void
-_rpmalloc_heap_global_finalize(heap_t * heap) {
- if (heap->finalize++ > 1) {
- --heap->finalize;
- return;
- }
-
- _rpmalloc_heap_finalize(heap);
-
-#if ENABLE_THREAD_CACHE
- for (size_t iclass = 0; iclass < LARGE_CLASS_COUNT; ++iclass) {
- span_cache_t* span_cache;
- if (!iclass)
- span_cache = &heap->span_cache;
- else
- span_cache = (span_cache_t*)(heap->span_large_cache + (iclass - 1));
- for (size_t ispan = 0; ispan < span_cache->count; ++ispan)
- _rpmalloc_span_unmap(span_cache->span[ispan]);
- span_cache->count = 0;
- }
-#endif
-
- if (heap->full_span_count) {
- --heap->finalize;
- return;
- }
-
- for (size_t iclass = 0; iclass < SIZE_CLASS_COUNT; ++iclass) {
- if (heap->size_class[iclass].free_list || heap->size_class[iclass].partial_span) {
- --heap->finalize;
- return;
- }
- }
- //Heap is now completely free, unmap and remove from heap list
- size_t list_idx = (size_t)heap->id % HEAP_ARRAY_SIZE;
- heap_t* list_heap = _memory_heaps[list_idx];
- if (list_heap == heap) {
- _memory_heaps[list_idx] = heap->next_heap;
- }
- else {
- while (list_heap->next_heap != heap)
- list_heap = list_heap->next_heap;
- list_heap->next_heap = heap->next_heap;
- }
-
- _rpmalloc_heap_unmap(heap);
-}
-
-//! Insert a single span into thread heap cache, releasing to global cache if overflow
-static void
-_rpmalloc_heap_cache_insert(heap_t * heap, span_t * span) {
- if (UNEXPECTED(heap->finalize != 0)) {
- _rpmalloc_span_unmap(span);
- _rpmalloc_heap_global_finalize(heap);
- return;
- }
-#if ENABLE_THREAD_CACHE
- size_t span_count = span->span_count;
- _rpmalloc_stat_inc(&heap->span_use[span_count - 1].spans_to_cache);
- if (span_count == 1) {
- span_cache_t* span_cache = &heap->span_cache;
- span_cache->span[span_cache->count++] = span;
- if (span_cache->count == MAX_THREAD_SPAN_CACHE) {
- const size_t remain_count = MAX_THREAD_SPAN_CACHE - THREAD_SPAN_CACHE_TRANSFER;
-#if ENABLE_GLOBAL_CACHE
- _rpmalloc_stat_add64(&heap->thread_to_global, THREAD_SPAN_CACHE_TRANSFER * _memory_span_size);
- _rpmalloc_stat_add(&heap->span_use[span_count - 1].spans_to_global, THREAD_SPAN_CACHE_TRANSFER);
- _rpmalloc_global_cache_insert_spans(span_cache->span + remain_count, span_count, THREAD_SPAN_CACHE_TRANSFER);
-#else
- for (size_t ispan = 0; ispan < THREAD_SPAN_CACHE_TRANSFER; ++ispan)
- _rpmalloc_span_unmap(span_cache->span[remain_count + ispan]);
-#endif
- span_cache->count = remain_count;
- }
- }
- else {
- size_t cache_idx = span_count - 2;
- span_large_cache_t* span_cache = heap->span_large_cache + cache_idx;
- span_cache->span[span_cache->count++] = span;
- const size_t cache_limit = (MAX_THREAD_SPAN_LARGE_CACHE - (span_count >> 1));
- if (span_cache->count == cache_limit) {
- const size_t transfer_limit = 2 + (cache_limit >> 2);
- const size_t transfer_count = (THREAD_SPAN_LARGE_CACHE_TRANSFER <= transfer_limit ? THREAD_SPAN_LARGE_CACHE_TRANSFER : transfer_limit);
- const size_t remain_count = cache_limit - transfer_count;
-#if ENABLE_GLOBAL_CACHE
- _rpmalloc_stat_add64(&heap->thread_to_global, transfer_count * span_count * _memory_span_size);
- _rpmalloc_stat_add(&heap->span_use[span_count - 1].spans_to_global, transfer_count);
- _rpmalloc_global_cache_insert_spans(span_cache->span + remain_count, span_count, transfer_count);
-#else
- for (size_t ispan = 0; ispan < transfer_count; ++ispan)
- _rpmalloc_span_unmap(span_cache->span[remain_count + ispan]);
-#endif
- span_cache->count = remain_count;
- }
- }
-#else
- (void)sizeof(heap);
- _rpmalloc_span_unmap(span);
-#endif
-}
-
-//! Extract the given number of spans from the different cache levels
-static span_t*
-_rpmalloc_heap_thread_cache_extract(heap_t * heap, size_t span_count) {
- span_t* span = 0;
-#if ENABLE_THREAD_CACHE
- span_cache_t* span_cache;
- if (span_count == 1)
- span_cache = &heap->span_cache;
- else
- span_cache = (span_cache_t*)(heap->span_large_cache + (span_count - 2));
- if (span_cache->count) {
- _rpmalloc_stat_inc(&heap->span_use[span_count - 1].spans_from_cache);
- return span_cache->span[--span_cache->count];
- }
-#endif
- return span;
-}
-
-static span_t*
-_rpmalloc_heap_thread_cache_deferred_extract(heap_t * heap, size_t span_count) {
- span_t* span = 0;
- if (span_count == 1) {
- _rpmalloc_heap_cache_adopt_deferred(heap, &span);
- }
- else {
- _rpmalloc_heap_cache_adopt_deferred(heap, 0);
- span = _rpmalloc_heap_thread_cache_extract(heap, span_count);
- }
- return span;
-}
-
-static span_t*
-_rpmalloc_heap_reserved_extract(heap_t * heap, size_t span_count) {
- if (heap->spans_reserved >= span_count)
- return _rpmalloc_span_map(heap, span_count);
- return 0;
-}
-
-//! Extract a span from the global cache
-static span_t*
-_rpmalloc_heap_global_cache_extract(heap_t * heap, size_t span_count) {
-#if ENABLE_GLOBAL_CACHE
-#if ENABLE_THREAD_CACHE
- span_cache_t* span_cache;
- size_t wanted_count;
- if (span_count == 1) {
- span_cache = &heap->span_cache;
- wanted_count = THREAD_SPAN_CACHE_TRANSFER;
- }
- else {
- span_cache = (span_cache_t*)(heap->span_large_cache + (span_count - 2));
- wanted_count = THREAD_SPAN_LARGE_CACHE_TRANSFER;
- }
- span_cache->count = _rpmalloc_global_cache_extract_spans(span_cache->span, span_count, wanted_count);
- if (span_cache->count) {
- _rpmalloc_stat_add64(&heap->global_to_thread, span_count * span_cache->count * _memory_span_size);
- _rpmalloc_stat_add(&heap->span_use[span_count - 1].spans_from_global, span_cache->count);
- return span_cache->span[--span_cache->count];
- }
-#else
- span_t* span = 0;
- size_t count = _rpmalloc_global_cache_extract_spans(&span, span_count, 1);
- if (count) {
- _rpmalloc_stat_add64(&heap->global_to_thread, span_count * count * _memory_span_size);
- _rpmalloc_stat_add(&heap->span_use[span_count - 1].spans_from_global, count);
- return span;
- }
-#endif
-#endif
- (void)sizeof(heap);
- (void)sizeof(span_count);
- return 0;
-}
-
-static void
-_rpmalloc_inc_span_statistics(heap_t * heap, size_t span_count, uint32_t class_idx) {
- (void)sizeof(heap);
- (void)sizeof(span_count);
- (void)sizeof(class_idx);
-#if ENABLE_ADAPTIVE_THREAD_CACHE || ENABLE_STATISTICS
- uint32_t idx = (uint32_t)span_count - 1;
- uint32_t current_count = (uint32_t)atomic_incr32(&heap->span_use[idx].current);
- if (current_count > (uint32_t)atomic_load32(&heap->span_use[idx].high))
- atomic_store32(&heap->span_use[idx].high, (int32_t)current_count);
- _rpmalloc_stat_add_peak(&heap->size_class_use[class_idx].spans_current, 1, heap->size_class_use[class_idx].spans_peak);
-#endif
-}
-
-//! Get a span from one of the cache levels (thread cache, reserved, global cache) or fallback to mapping more memory
-static span_t*
-_rpmalloc_heap_extract_new_span(heap_t * heap, heap_size_class_t * heap_size_class, size_t span_count, uint32_t class_idx) {
- span_t* span;
-#if ENABLE_THREAD_CACHE
- if (heap_size_class && heap_size_class->cache) {
- span = heap_size_class->cache;
- heap_size_class->cache = (heap->span_cache.count ? heap->span_cache.span[--heap->span_cache.count] : 0);
- _rpmalloc_inc_span_statistics(heap, span_count, class_idx);
- return span;
- }
-#endif
- (void)sizeof(class_idx);
- // Allow 50% overhead to increase cache hits
- size_t base_span_count = span_count;
- size_t limit_span_count = (span_count > 2) ? (span_count + (span_count >> 1)) : span_count;
- if (limit_span_count > LARGE_CLASS_COUNT)
- limit_span_count = LARGE_CLASS_COUNT;
- do {
- span = _rpmalloc_heap_thread_cache_extract(heap, span_count);
- if (EXPECTED(span != 0)) {
- _rpmalloc_stat_inc(&heap->size_class_use[class_idx].spans_from_cache);
- _rpmalloc_inc_span_statistics(heap, span_count, class_idx);
- return span;
- }
- span = _rpmalloc_heap_thread_cache_deferred_extract(heap, span_count);
- if (EXPECTED(span != 0)) {
- _rpmalloc_stat_inc(&heap->size_class_use[class_idx].spans_from_cache);
- _rpmalloc_inc_span_statistics(heap, span_count, class_idx);
- return span;
- }
- span = _rpmalloc_heap_reserved_extract(heap, span_count);
- if (EXPECTED(span != 0)) {
- _rpmalloc_stat_inc(&heap->size_class_use[class_idx].spans_from_reserved);
- _rpmalloc_inc_span_statistics(heap, span_count, class_idx);
- return span;
- }
- span = _rpmalloc_heap_global_cache_extract(heap, span_count);
- if (EXPECTED(span != 0)) {
- _rpmalloc_stat_inc(&heap->size_class_use[class_idx].spans_from_cache);
- _rpmalloc_inc_span_statistics(heap, span_count, class_idx);
- return span;
- }
- ++span_count;
- } while (span_count <= limit_span_count);
- //Final fallback, map in more virtual memory
- span = _rpmalloc_span_map(heap, base_span_count);
- _rpmalloc_inc_span_statistics(heap, base_span_count, class_idx);
- _rpmalloc_stat_inc(&heap->size_class_use[class_idx].spans_map_calls);
- return span;
-}
-
-static void
-_rpmalloc_heap_initialize(heap_t * heap) {
- _rpmalloc_memset_const(heap, 0, sizeof(heap_t));
- //Get a new heap ID
- heap->id = 1 + atomic_incr32(&_memory_heap_id);
-
- //Link in heap in heap ID map
- size_t list_idx = (size_t)heap->id % HEAP_ARRAY_SIZE;
- heap->next_heap = _memory_heaps[list_idx];
- _memory_heaps[list_idx] = heap;
-}
-
-static void
-_rpmalloc_heap_orphan(heap_t * heap, int first_class) {
- heap->owner_thread = (uintptr_t)-1;
-#if RPMALLOC_FIRST_CLASS_HEAPS
- heap_t** heap_list = (first_class ? &_memory_first_class_orphan_heaps : &_memory_orphan_heaps);
-#else
- (void)sizeof(first_class);
- heap_t** heap_list = &_memory_orphan_heaps;
-#endif
- heap->next_orphan = *heap_list;
- *heap_list = heap;
-}
-
-//! Allocate a new heap from newly mapped memory pages
-static heap_t*
-_rpmalloc_heap_allocate_new(void) {
- // Map in pages for a 16 heaps. If page size is greater than required size for this, map a page and
- // use first part for heaps and remaining part for spans for allocations. Adds a lot of complexity,
- // but saves a lot of memory on systems where page size > 64 spans (4MiB)
- size_t heap_size = sizeof(heap_t);
- size_t aligned_heap_size = 16 * ((heap_size + 15) / 16);
- size_t request_heap_count = 16;
- size_t heap_span_count = ((aligned_heap_size * request_heap_count) + sizeof(span_t) + _memory_span_size - 1) / _memory_span_size;
- size_t block_size = _memory_span_size * heap_span_count;
- size_t span_count = heap_span_count;
- span_t* span = 0;
- // If there are global reserved spans, use these first
- if (_memory_global_reserve_count >= heap_span_count) {
- span = _rpmalloc_global_get_reserved_spans(heap_span_count);
- }
- if (!span) {
- if (_memory_page_size > block_size) {
- span_count = _memory_page_size / _memory_span_size;
- block_size = _memory_page_size;
- // If using huge pages, make sure to grab enough heaps to avoid reallocating a huge page just to serve new heaps
- size_t possible_heap_count = (block_size - sizeof(span_t)) / aligned_heap_size;
- if (possible_heap_count >= (request_heap_count * 16))
- request_heap_count *= 16;
- else if (possible_heap_count < request_heap_count)
- request_heap_count = possible_heap_count;
- heap_span_count = ((aligned_heap_size * request_heap_count) + sizeof(span_t) + _memory_span_size - 1) / _memory_span_size;
- }
-
- size_t align_offset = 0;
- span = (span_t*)_rpmalloc_mmap(block_size, &align_offset);
- if (!span)
- return 0;
-
- // Master span will contain the heaps
- _rpmalloc_stat_inc(&_master_spans);
- _rpmalloc_span_initialize(span, span_count, heap_span_count, align_offset);
- }
-
- size_t remain_size = _memory_span_size - sizeof(span_t);
- heap_t* heap = (heap_t*)pointer_offset(span, sizeof(span_t));
- _rpmalloc_heap_initialize(heap);
-
- // Put extra heaps as orphans
- size_t num_heaps = remain_size / aligned_heap_size;
- if (num_heaps < request_heap_count)
- num_heaps = request_heap_count;
- atomic_store32(&heap->child_count, (int32_t)num_heaps - 1);
- heap_t* extra_heap = (heap_t*)pointer_offset(heap, aligned_heap_size);
- while (num_heaps > 1) {
- _rpmalloc_heap_initialize(extra_heap);
- extra_heap->master_heap = heap;
- _rpmalloc_heap_orphan(extra_heap, 1);
- extra_heap = (heap_t*)pointer_offset(extra_heap, aligned_heap_size);
- --num_heaps;
- }
-
- if (span_count > heap_span_count) {
- // Cap reserved spans
- size_t remain_count = span_count - heap_span_count;
- size_t reserve_count = (remain_count > _memory_heap_reserve_count ? _memory_heap_reserve_count : remain_count);
- span_t* remain_span = (span_t*)pointer_offset(span, heap_span_count * _memory_span_size);
- _rpmalloc_heap_set_reserved_spans(heap, span, remain_span, reserve_count);
-
- if (remain_count > reserve_count) {
- // Set to global reserved spans
- remain_span = (span_t*)pointer_offset(remain_span, reserve_count * _memory_span_size);
- reserve_count = remain_count - reserve_count;
- _rpmalloc_global_set_reserved_spans(span, remain_span, reserve_count);
- }
- }
-
- return heap;
-}
-
-static heap_t*
-_rpmalloc_heap_extract_orphan(heap_t * *heap_list) {
- heap_t* heap = *heap_list;
- *heap_list = (heap ? heap->next_orphan : 0);
- return heap;
-}
-
-//! Allocate a new heap, potentially reusing a previously orphaned heap
-static heap_t*
-_rpmalloc_heap_allocate(int first_class) {
- heap_t* heap = 0;
- while (!atomic_cas32_acquire(&_memory_global_lock, 1, 0))
- _rpmalloc_spin();
- if (first_class == 0)
- heap = _rpmalloc_heap_extract_orphan(&_memory_orphan_heaps);
-#if RPMALLOC_FIRST_CLASS_HEAPS
- if (!heap)
- heap = _rpmalloc_heap_extract_orphan(&_memory_first_class_orphan_heaps);
-#endif
- if (!heap)
- heap = _rpmalloc_heap_allocate_new();
- atomic_store32_release(&_memory_global_lock, 0);
- if (heap)
- _rpmalloc_heap_cache_adopt_deferred(heap, 0);
- return heap;
-}
-
-static void
-_rpmalloc_heap_release(void* heapptr, int first_class, int release_cache) {
- heap_t* heap = (heap_t*)heapptr;
- if (!heap)
- return;
- //Release thread cache spans back to global cache
- _rpmalloc_heap_cache_adopt_deferred(heap, 0);
- if (release_cache || heap->finalize) {
-#if ENABLE_THREAD_CACHE
- for (size_t iclass = 0; iclass < LARGE_CLASS_COUNT; ++iclass) {
- span_cache_t* span_cache;
- if (!iclass)
- span_cache = &heap->span_cache;
- else
- span_cache = (span_cache_t*)(heap->span_large_cache + (iclass - 1));
- if (!span_cache->count)
- continue;
-#if ENABLE_GLOBAL_CACHE
- if (heap->finalize) {
- for (size_t ispan = 0; ispan < span_cache->count; ++ispan)
- _rpmalloc_span_unmap(span_cache->span[ispan]);
- }
- else {
- _rpmalloc_stat_add64(&heap->thread_to_global, span_cache->count * (iclass + 1) * _memory_span_size);
- _rpmalloc_stat_add(&heap->span_use[iclass].spans_to_global, span_cache->count);
- _rpmalloc_global_cache_insert_spans(span_cache->span, iclass + 1, span_cache->count);
- }
-#else
- for (size_t ispan = 0; ispan < span_cache->count; ++ispan)
- _rpmalloc_span_unmap(span_cache->span[ispan]);
-#endif
- span_cache->count = 0;
- }
-#endif
- }
-
- if (get_thread_heap_raw() == heap)
- set_thread_heap(0);
-
-#if ENABLE_STATISTICS
- atomic_decr32(&_memory_active_heaps);
- rpmalloc_assert(atomic_load32(&_memory_active_heaps) >= 0, "Still active heaps during finalization");
-#endif
-
- // If we are forcibly terminating with _exit the state of the
- // lock atomic is unknown and it's best to just go ahead and exit
- if (get_thread_id() != _rpmalloc_main_thread_id) {
- while (!atomic_cas32_acquire(&_memory_global_lock, 1, 0))
- _rpmalloc_spin();
- }
- _rpmalloc_heap_orphan(heap, first_class);
- atomic_store32_release(&_memory_global_lock, 0);
-}
-
-static void
-_rpmalloc_heap_release_raw(void* heapptr, int release_cache) {
- _rpmalloc_heap_release(heapptr, 0, release_cache);
-}
-
-static void
-_rpmalloc_heap_release_raw_fc(void* heapptr) {
- _rpmalloc_heap_release_raw(heapptr, 1);
-}
-
-static void
-_rpmalloc_heap_finalize(heap_t * heap) {
- if (heap->spans_reserved) {
- span_t* span = _rpmalloc_span_map(heap, heap->spans_reserved);
- _rpmalloc_span_unmap(span);
- heap->spans_reserved = 0;
- }
-
- _rpmalloc_heap_cache_adopt_deferred(heap, 0);
-
- for (size_t iclass = 0; iclass < SIZE_CLASS_COUNT; ++iclass) {
- if (heap->size_class[iclass].cache)
- _rpmalloc_span_unmap(heap->size_class[iclass].cache);
- heap->size_class[iclass].cache = 0;
- span_t* span = heap->size_class[iclass].partial_span;
- while (span) {
- span_t* next = span->next;
- _rpmalloc_span_finalize(heap, iclass, span, &heap->size_class[iclass].partial_span);
- span = next;
- }
- // If class still has a free list it must be a full span
- if (heap->size_class[iclass].free_list) {
- span_t* class_span = (span_t*)((uintptr_t)heap->size_class[iclass].free_list & _memory_span_mask);
- span_t** list = 0;
-#if RPMALLOC_FIRST_CLASS_HEAPS
- list = &heap->full_span[iclass];
-#endif
- --heap->full_span_count;
- if (!_rpmalloc_span_finalize(heap, iclass, class_span, list)) {
- if (list)
- _rpmalloc_span_double_link_list_remove(list, class_span);
- _rpmalloc_span_double_link_list_add(&heap->size_class[iclass].partial_span, class_span);
- }
- }
- }
-
-#if ENABLE_THREAD_CACHE
- for (size_t iclass = 0; iclass < LARGE_CLASS_COUNT; ++iclass) {
- span_cache_t* span_cache;
- if (!iclass)
- span_cache = &heap->span_cache;
- else
- span_cache = (span_cache_t*)(heap->span_large_cache + (iclass - 1));
- for (size_t ispan = 0; ispan < span_cache->count; ++ispan)
- _rpmalloc_span_unmap(span_cache->span[ispan]);
- span_cache->count = 0;
- }
-#endif
- rpmalloc_assert(!atomic_load_ptr(&heap->span_free_deferred), "Heaps still active during finalization");
-}
-
-
-////////////
-///
-/// Allocation entry points
-///
-//////
-
-//! Pop first block from a free list
-static void*
-free_list_pop(void** list) {
- void* block = *list;
- *list = *((void**)block);
- return block;
-}
-
-//! Allocate a small/medium sized memory block from the given heap
-static void*
-_rpmalloc_allocate_from_heap_fallback(heap_t * heap, heap_size_class_t * heap_size_class, uint32_t class_idx) {
- span_t* span = heap_size_class->partial_span;
- rpmalloc_assume(heap);
- if (EXPECTED(span != 0)) {
- rpmalloc_assert(span->block_count == _memory_size_class[span->size_class].block_count, "Span block count corrupted");
- rpmalloc_assert(!_rpmalloc_span_is_fully_utilized(span), "Internal failure");
- void* block;
- if (span->free_list) {
- //Span local free list is not empty, swap to size class free list
- block = free_list_pop(&span->free_list);
- heap_size_class->free_list = span->free_list;
- span->free_list = 0;
- }
- else {
- //If the span did not fully initialize free list, link up another page worth of blocks
- void* block_start = pointer_offset(span, SPAN_HEADER_SIZE + ((size_t)span->free_list_limit * span->block_size));
- span->free_list_limit += free_list_partial_init(&heap_size_class->free_list, &block,
- (void*)((uintptr_t)block_start & ~(_memory_page_size - 1)), block_start,
- span->block_count - span->free_list_limit, span->block_size);
- }
- rpmalloc_assert(span->free_list_limit <= span->block_count, "Span block count corrupted");
- span->used_count = span->free_list_limit;
-
- //Swap in deferred free list if present
- if (atomic_load_ptr(&span->free_list_deferred))
- _rpmalloc_span_extract_free_list_deferred(span);
-
- //If span is still not fully utilized keep it in partial list and early return block
- if (!_rpmalloc_span_is_fully_utilized(span))
- return block;
-
- //The span is fully utilized, unlink from partial list and add to fully utilized list
- _rpmalloc_span_double_link_list_pop_head(&heap_size_class->partial_span, span);
-#if RPMALLOC_FIRST_CLASS_HEAPS
- _rpmalloc_span_double_link_list_add(&heap->full_span[class_idx], span);
-#endif
- ++heap->full_span_count;
- return block;
- }
-
- //Find a span in one of the cache levels
- span = _rpmalloc_heap_extract_new_span(heap, heap_size_class, 1, class_idx);
- if (EXPECTED(span != 0)) {
- //Mark span as owned by this heap and set base data, return first block
- return _rpmalloc_span_initialize_new(heap, heap_size_class, span, class_idx);
- }
-
- return 0;
-}
-
-//! Allocate a small sized memory block from the given heap
-static void*
-_rpmalloc_allocate_small(heap_t * heap, size_t size) {
- rpmalloc_assert(heap, "No thread heap");
- //Small sizes have unique size classes
- const uint32_t class_idx = (uint32_t)((size + (SMALL_GRANULARITY - 1)) >> SMALL_GRANULARITY_SHIFT);
- heap_size_class_t* heap_size_class = heap->size_class + class_idx;
- _rpmalloc_stat_inc_alloc(heap, class_idx);
- if (EXPECTED(heap_size_class->free_list != 0))
- return free_list_pop(&heap_size_class->free_list);
- return _rpmalloc_allocate_from_heap_fallback(heap, heap_size_class, class_idx);
-}
-
-//! Allocate a medium sized memory block from the given heap
-static void*
-_rpmalloc_allocate_medium(heap_t * heap, size_t size) {
- rpmalloc_assert(heap, "No thread heap");
- //Calculate the size class index and do a dependent lookup of the final class index (in case of merged classes)
- const uint32_t base_idx = (uint32_t)(SMALL_CLASS_COUNT + ((size - (SMALL_SIZE_LIMIT + 1)) >> MEDIUM_GRANULARITY_SHIFT));
- const uint32_t class_idx = _memory_size_class[base_idx].class_idx;
- heap_size_class_t* heap_size_class = heap->size_class + class_idx;
- _rpmalloc_stat_inc_alloc(heap, class_idx);
- if (EXPECTED(heap_size_class->free_list != 0))
- return free_list_pop(&heap_size_class->free_list);
- return _rpmalloc_allocate_from_heap_fallback(heap, heap_size_class, class_idx);
-}
-
-//! Allocate a large sized memory block from the given heap
-static void*
-_rpmalloc_allocate_large(heap_t * heap, size_t size) {
- rpmalloc_assert(heap, "No thread heap");
- //Calculate number of needed max sized spans (including header)
- //Since this function is never called if size > LARGE_SIZE_LIMIT
- //the span_count is guaranteed to be <= LARGE_CLASS_COUNT
- size += SPAN_HEADER_SIZE;
- size_t span_count = size >> _memory_span_size_shift;
- if (size & (_memory_span_size - 1))
- ++span_count;
-
- //Find a span in one of the cache levels
- span_t* span = _rpmalloc_heap_extract_new_span(heap, 0, span_count, SIZE_CLASS_LARGE);
- if (!span)
- return span;
-
- //Mark span as owned by this heap and set base data
- rpmalloc_assert(span->span_count >= span_count, "Internal failure");
- span->size_class = SIZE_CLASS_LARGE;
- span->heap = heap;
-
-#if RPMALLOC_FIRST_CLASS_HEAPS
- _rpmalloc_span_double_link_list_add(&heap->large_huge_span, span);
-#endif
- ++heap->full_span_count;
-
- return pointer_offset(span, SPAN_HEADER_SIZE);
-}
-
-//! Allocate a huge block by mapping memory pages directly
-static void*
-_rpmalloc_allocate_huge(heap_t * heap, size_t size) {
- rpmalloc_assert(heap, "No thread heap");
- _rpmalloc_heap_cache_adopt_deferred(heap, 0);
- size += SPAN_HEADER_SIZE;
- size_t num_pages = size >> _memory_page_size_shift;
- if (size & (_memory_page_size - 1))
- ++num_pages;
- size_t align_offset = 0;
- span_t* span = (span_t*)_rpmalloc_mmap(num_pages * _memory_page_size, &align_offset);
- if (!span)
- return span;
-
- //Store page count in span_count
- span->size_class = SIZE_CLASS_HUGE;
- span->span_count = (uint32_t)num_pages;
- span->align_offset = (uint32_t)align_offset;
- span->heap = heap;
- _rpmalloc_stat_add_peak(&_huge_pages_current, num_pages, _huge_pages_peak);
-
-#if RPMALLOC_FIRST_CLASS_HEAPS
- _rpmalloc_span_double_link_list_add(&heap->large_huge_span, span);
-#endif
- ++heap->full_span_count;
-
- return pointer_offset(span, SPAN_HEADER_SIZE);
-}
-
-//! Allocate a block of the given size
-static void*
-_rpmalloc_allocate(heap_t * heap, size_t size) {
- _rpmalloc_stat_add64(&_allocation_counter, 1);
- if (EXPECTED(size <= SMALL_SIZE_LIMIT))
- return _rpmalloc_allocate_small(heap, size);
- else if (size <= _memory_medium_size_limit)
- return _rpmalloc_allocate_medium(heap, size);
- else if (size <= LARGE_SIZE_LIMIT)
- return _rpmalloc_allocate_large(heap, size);
- return _rpmalloc_allocate_huge(heap, size);
-}
-
-static void*
-_rpmalloc_aligned_allocate(heap_t * heap, size_t alignment, size_t size) {
- if (alignment <= SMALL_GRANULARITY)
- return _rpmalloc_allocate(heap, size);
-
-#if ENABLE_VALIDATE_ARGS
- if ((size + alignment) < size) {
- errno = EINVAL;
- return 0;
- }
- if (alignment & (alignment - 1)) {
- errno = EINVAL;
- return 0;
- }
-#endif
-
- if ((alignment <= SPAN_HEADER_SIZE) && ((size + SPAN_HEADER_SIZE) < _memory_medium_size_limit)) {
- // If alignment is less or equal to span header size (which is power of two),
- // and size aligned to span header size multiples is less than size + alignment,
- // then use natural alignment of blocks to provide alignment
- size_t multiple_size = size ? (size + (SPAN_HEADER_SIZE - 1)) & ~(uintptr_t)(SPAN_HEADER_SIZE - 1) : SPAN_HEADER_SIZE;
- rpmalloc_assert(!(multiple_size % SPAN_HEADER_SIZE), "Failed alignment calculation");
- if (multiple_size <= (size + alignment))
- return _rpmalloc_allocate(heap, multiple_size);
- }
-
- void* ptr = 0;
- size_t align_mask = alignment - 1;
- if (alignment <= _memory_page_size) {
- ptr = _rpmalloc_allocate(heap, size + alignment);
- if ((uintptr_t)ptr & align_mask) {
- ptr = (void*)(((uintptr_t)ptr & ~(uintptr_t)align_mask) + alignment);
- //Mark as having aligned blocks
- span_t* span = (span_t*)((uintptr_t)ptr & _memory_span_mask);
- span->flags |= SPAN_FLAG_ALIGNED_BLOCKS;
- }
- return ptr;
- }
-
- // Fallback to mapping new pages for this request. Since pointers passed
- // to rpfree must be able to reach the start of the span by bitmasking of
- // the address with the span size, the returned aligned pointer from this
- // function must be with a span size of the start of the mapped area.
- // In worst case this requires us to loop and map pages until we get a
- // suitable memory address. It also means we can never align to span size
- // or greater, since the span header will push alignment more than one
- // span size away from span start (thus causing pointer mask to give us
- // an invalid span start on free)
- if (alignment & align_mask) {
- errno = EINVAL;
- return 0;
- }
- if (alignment >= _memory_span_size) {
- errno = EINVAL;
- return 0;
- }
-
- size_t extra_pages = alignment / _memory_page_size;
-
- // Since each span has a header, we will at least need one extra memory page
- size_t num_pages = 1 + (size / _memory_page_size);
- if (size & (_memory_page_size - 1))
- ++num_pages;
-
- if (extra_pages > num_pages)
- num_pages = 1 + extra_pages;
-
- size_t original_pages = num_pages;
- size_t limit_pages = (_memory_span_size / _memory_page_size) * 2;
- if (limit_pages < (original_pages * 2))
- limit_pages = original_pages * 2;
-
- size_t mapped_size, align_offset;
- span_t* span;
-
-retry:
- align_offset = 0;
- mapped_size = num_pages * _memory_page_size;
-
- span = (span_t*)_rpmalloc_mmap(mapped_size, &align_offset);
- if (!span) {
- errno = ENOMEM;
- return 0;
- }
- ptr = pointer_offset(span, SPAN_HEADER_SIZE);
-
- if ((uintptr_t)ptr & align_mask)
- ptr = (void*)(((uintptr_t)ptr & ~(uintptr_t)align_mask) + alignment);
-
- if (((size_t)pointer_diff(ptr, span) >= _memory_span_size) ||
- (pointer_offset(ptr, size) > pointer_offset(span, mapped_size)) ||
- (((uintptr_t)ptr & _memory_span_mask) != (uintptr_t)span)) {
- _rpmalloc_unmap(span, mapped_size, align_offset, mapped_size);
- ++num_pages;
- if (num_pages > limit_pages) {
- errno = EINVAL;
- return 0;
- }
- goto retry;
- }
-
- //Store page count in span_count
- span->size_class = SIZE_CLASS_HUGE;
- span->span_count = (uint32_t)num_pages;
- span->align_offset = (uint32_t)align_offset;
- span->heap = heap;
- _rpmalloc_stat_add_peak(&_huge_pages_current, num_pages, _huge_pages_peak);
-
-#if RPMALLOC_FIRST_CLASS_HEAPS
- _rpmalloc_span_double_link_list_add(&heap->large_huge_span, span);
-#endif
- ++heap->full_span_count;
-
- _rpmalloc_stat_add64(&_allocation_counter, 1);
-
- return ptr;
-}
-
-
-////////////
-///
-/// Deallocation entry points
-///
-//////
-
-//! Deallocate the given small/medium memory block in the current thread local heap
-static void
-_rpmalloc_deallocate_direct_small_or_medium(span_t * span, void* block) {
- heap_t* heap = span->heap;
- rpmalloc_assert(heap->owner_thread == get_thread_id() || !heap->owner_thread || heap->finalize, "Internal failure");
- //Add block to free list
- if (UNEXPECTED(_rpmalloc_span_is_fully_utilized(span))) {
- span->used_count = span->block_count;
-#if RPMALLOC_FIRST_CLASS_HEAPS
- _rpmalloc_span_double_link_list_remove(&heap->full_span[span->size_class], span);
-#endif
- _rpmalloc_span_double_link_list_add(&heap->size_class[span->size_class].partial_span, span);
- --heap->full_span_count;
- }
- *((void**)block) = span->free_list;
- --span->used_count;
- span->free_list = block;
- if (UNEXPECTED(span->used_count == span->list_size)) {
- // If there are no used blocks it is guaranteed that no other external thread is accessing the span
- if (span->used_count) {
- // Make sure we have synchronized the deferred list and list size by using acquire semantics
- // and guarantee that no external thread is accessing span concurrently
- void* free_list;
- do {
- free_list = atomic_exchange_ptr_acquire(&span->free_list_deferred, INVALID_POINTER);
- } while (free_list == INVALID_POINTER);
- atomic_store_ptr_release(&span->free_list_deferred, free_list);
- }
- _rpmalloc_span_double_link_list_remove(&heap->size_class[span->size_class].partial_span, span);
- _rpmalloc_span_release_to_cache(heap, span);
- }
-}
-
-static void
-_rpmalloc_deallocate_defer_free_span(heap_t * heap, span_t * span) {
- if (span->size_class != SIZE_CLASS_HUGE)
- _rpmalloc_stat_inc(&heap->span_use[span->span_count - 1].spans_deferred);
- //This list does not need ABA protection, no mutable side state
- do {
- span->free_list = (void*)atomic_load_ptr(&heap->span_free_deferred);
- } while (!atomic_cas_ptr(&heap->span_free_deferred, span, span->free_list));
-}
-
-//! Put the block in the deferred free list of the owning span
-static void
-_rpmalloc_deallocate_defer_small_or_medium(span_t * span, void* block) {
- // The memory ordering here is a bit tricky, to avoid having to ABA protect
- // the deferred free list to avoid desynchronization of list and list size
- // we need to have acquire semantics on successful CAS of the pointer to
- // guarantee the list_size variable validity + release semantics on pointer store
- void* free_list;
- do {
- free_list = atomic_exchange_ptr_acquire(&span->free_list_deferred, INVALID_POINTER);
- } while (free_list == INVALID_POINTER);
- *((void**)block) = free_list;
- uint32_t free_count = ++span->list_size;
- int all_deferred_free = (free_count == span->block_count);
- atomic_store_ptr_release(&span->free_list_deferred, block);
- if (all_deferred_free) {
- // Span was completely freed by this block. Due to the INVALID_POINTER spin lock
- // no other thread can reach this state simultaneously on this span.
- // Safe to move to owner heap deferred cache
- _rpmalloc_deallocate_defer_free_span(span->heap, span);
- }
-}
-
-static void
-_rpmalloc_deallocate_small_or_medium(span_t * span, void* p) {
- _rpmalloc_stat_inc_free(span->heap, span->size_class);
- if (span->flags & SPAN_FLAG_ALIGNED_BLOCKS) {
- //Realign pointer to block start
- void* blocks_start = pointer_offset(span, SPAN_HEADER_SIZE);
- uint32_t block_offset = (uint32_t)pointer_diff(p, blocks_start);
- p = pointer_offset(p, -(int32_t)(block_offset % span->block_size));
- }
- //Check if block belongs to this heap or if deallocation should be deferred
-#if RPMALLOC_FIRST_CLASS_HEAPS
- int defer = (span->heap->owner_thread && (span->heap->owner_thread != get_thread_id()) && !span->heap->finalize);
-#else
- int defer = ((span->heap->owner_thread != get_thread_id()) && !span->heap->finalize);
-#endif
- if (!defer)
- _rpmalloc_deallocate_direct_small_or_medium(span, p);
- else
- _rpmalloc_deallocate_defer_small_or_medium(span, p);
-}
-
-//! Deallocate the given large memory block to the current heap
-static void
-_rpmalloc_deallocate_large(span_t * span) {
- rpmalloc_assert(span->size_class == SIZE_CLASS_LARGE, "Bad span size class");
- rpmalloc_assert(!(span->flags & SPAN_FLAG_MASTER) || !(span->flags & SPAN_FLAG_SUBSPAN), "Span flag corrupted");
- rpmalloc_assert((span->flags & SPAN_FLAG_MASTER) || (span->flags & SPAN_FLAG_SUBSPAN), "Span flag corrupted");
- //We must always defer (unless finalizing) if from another heap since we cannot touch the list or counters of another heap
-#if RPMALLOC_FIRST_CLASS_HEAPS
- int defer = (span->heap->owner_thread && (span->heap->owner_thread != get_thread_id()) && !span->heap->finalize);
-#else
- int defer = ((span->heap->owner_thread != get_thread_id()) && !span->heap->finalize);
-#endif
- if (defer) {
- _rpmalloc_deallocate_defer_free_span(span->heap, span);
- return;
- }
- rpmalloc_assert(span->heap->full_span_count, "Heap span counter corrupted");
- --span->heap->full_span_count;
-#if RPMALLOC_FIRST_CLASS_HEAPS
- _rpmalloc_span_double_link_list_remove(&span->heap->large_huge_span, span);
-#endif
-#if ENABLE_ADAPTIVE_THREAD_CACHE || ENABLE_STATISTICS
- //Decrease counter
- size_t idx = span->span_count - 1;
- atomic_decr32(&span->heap->span_use[idx].current);
-#endif
- heap_t* heap = span->heap;
- rpmalloc_assert(heap, "No thread heap");
-#if ENABLE_THREAD_CACHE
- const int set_as_reserved = ((span->span_count > 1) && (heap->span_cache.count == 0) && !heap->finalize && !heap->spans_reserved);
-#else
- const int set_as_reserved = ((span->span_count > 1) && !heap->finalize && !heap->spans_reserved);
-#endif
- if (set_as_reserved) {
- heap->span_reserve = span;
- heap->spans_reserved = span->span_count;
- if (span->flags & SPAN_FLAG_MASTER) {
- heap->span_reserve_master = span;
- }
- else { //SPAN_FLAG_SUBSPAN
- span_t* master = (span_t*)pointer_offset(span, -(intptr_t)((size_t)span->offset_from_master * _memory_span_size));
- heap->span_reserve_master = master;
- rpmalloc_assert(master->flags & SPAN_FLAG_MASTER, "Span flag corrupted");
- rpmalloc_assert(atomic_load32(&master->remaining_spans) >= (int32_t)span->span_count, "Master span count corrupted");
- }
- _rpmalloc_stat_inc(&heap->span_use[idx].spans_to_reserved);
- }
- else {
- //Insert into cache list
- _rpmalloc_heap_cache_insert(heap, span);
- }
-}
-
-//! Deallocate the given huge span
-static void
-_rpmalloc_deallocate_huge(span_t * span) {
- rpmalloc_assert(span->heap, "No span heap");
-#if RPMALLOC_FIRST_CLASS_HEAPS
- int defer = (span->heap->owner_thread && (span->heap->owner_thread != get_thread_id()) && !span->heap->finalize);
-#else
- int defer = ((span->heap->owner_thread != get_thread_id()) && !span->heap->finalize);
-#endif
- if (defer) {
- _rpmalloc_deallocate_defer_free_span(span->heap, span);
- return;
- }
- rpmalloc_assert(span->heap->full_span_count, "Heap span counter corrupted");
- --span->heap->full_span_count;
-#if RPMALLOC_FIRST_CLASS_HEAPS
- _rpmalloc_span_double_link_list_remove(&span->heap->large_huge_span, span);
-#endif
-
- //Oversized allocation, page count is stored in span_count
- size_t num_pages = span->span_count;
- _rpmalloc_unmap(span, num_pages * _memory_page_size, span->align_offset, num_pages * _memory_page_size);
- _rpmalloc_stat_sub(&_huge_pages_current, num_pages);
-}
-
-//! Deallocate the given block
-static void
-_rpmalloc_deallocate(void* p) {
- _rpmalloc_stat_add64(&_deallocation_counter, 1);
- //Grab the span (always at start of span, using span alignment)
- span_t* span = (span_t*)((uintptr_t)p & _memory_span_mask);
- if (UNEXPECTED(!span))
- return;
- if (EXPECTED(span->size_class < SIZE_CLASS_COUNT))
- _rpmalloc_deallocate_small_or_medium(span, p);
- else if (span->size_class == SIZE_CLASS_LARGE)
- _rpmalloc_deallocate_large(span);
- else
- _rpmalloc_deallocate_huge(span);
-}
-
-////////////
-///
-/// Reallocation entry points
-///
-//////
-
-static size_t
-_rpmalloc_usable_size(void* p);
-
-//! Reallocate the given block to the given size
-static void*
-_rpmalloc_reallocate(heap_t * heap, void* p, size_t size, size_t oldsize, unsigned int flags) {
- if (p) {
- //Grab the span using guaranteed span alignment
- span_t* span = (span_t*)((uintptr_t)p & _memory_span_mask);
- if (EXPECTED(span->size_class < SIZE_CLASS_COUNT)) {
- //Small/medium sized block
- rpmalloc_assert(span->span_count == 1, "Span counter corrupted");
- void* blocks_start = pointer_offset(span, SPAN_HEADER_SIZE);
- uint32_t block_offset = (uint32_t)pointer_diff(p, blocks_start);
- uint32_t block_idx = block_offset / span->block_size;
- void* block = pointer_offset(blocks_start, (size_t)block_idx * span->block_size);
- if (!oldsize)
- oldsize = (size_t)((ptrdiff_t)span->block_size - pointer_diff(p, block));
- if ((size_t)span->block_size >= size) {
- //Still fits in block, never mind trying to save memory, but preserve data if alignment changed
- if ((p != block) && !(flags & RPMALLOC_NO_PRESERVE))
- memmove(block, p, oldsize);
- return block;
- }
- }
- else if (span->size_class == SIZE_CLASS_LARGE) {
- //Large block
- size_t total_size = size + SPAN_HEADER_SIZE;
- size_t num_spans = total_size >> _memory_span_size_shift;
- if (total_size & (_memory_span_mask - 1))
- ++num_spans;
- size_t current_spans = span->span_count;
- void* block = pointer_offset(span, SPAN_HEADER_SIZE);
- if (!oldsize)
- oldsize = (current_spans * _memory_span_size) - (size_t)pointer_diff(p, block) - SPAN_HEADER_SIZE;
- if ((current_spans >= num_spans) && (total_size >= (oldsize / 2))) {
- //Still fits in block, never mind trying to save memory, but preserve data if alignment changed
- if ((p != block) && !(flags & RPMALLOC_NO_PRESERVE))
- memmove(block, p, oldsize);
- return block;
- }
- }
- else {
- //Oversized block
- size_t total_size = size + SPAN_HEADER_SIZE;
- size_t num_pages = total_size >> _memory_page_size_shift;
- if (total_size & (_memory_page_size - 1))
- ++num_pages;
- //Page count is stored in span_count
- size_t current_pages = span->span_count;
- void* block = pointer_offset(span, SPAN_HEADER_SIZE);
- if (!oldsize)
- oldsize = (current_pages * _memory_page_size) - (size_t)pointer_diff(p, block) - SPAN_HEADER_SIZE;
- if ((current_pages >= num_pages) && (num_pages >= (current_pages / 2))) {
- //Still fits in block, never mind trying to save memory, but preserve data if alignment changed
- if ((p != block) && !(flags & RPMALLOC_NO_PRESERVE))
- memmove(block, p, oldsize);
- return block;
- }
- }
- }
- else {
- oldsize = 0;
- }
-
- if (!!(flags & RPMALLOC_GROW_OR_FAIL))
- return 0;
-
- //Size is greater than block size, need to allocate a new block and deallocate the old
- //Avoid hysteresis by overallocating if increase is small (below 37%)
- size_t lower_bound = oldsize + (oldsize >> 2) + (oldsize >> 3);
- size_t new_size = (size > lower_bound) ? size : ((size > oldsize) ? lower_bound : size);
- void* block = _rpmalloc_allocate(heap, new_size);
- if (p && block) {
- if (!(flags & RPMALLOC_NO_PRESERVE))
- memcpy(block, p, oldsize < new_size ? oldsize : new_size);
- _rpmalloc_deallocate(p);
- }
-
- return block;
-}
-
-static void*
-_rpmalloc_aligned_reallocate(heap_t * heap, void* ptr, size_t alignment, size_t size, size_t oldsize,
- unsigned int flags) {
- if (alignment <= SMALL_GRANULARITY)
- return _rpmalloc_reallocate(heap, ptr, size, oldsize, flags);
-
- int no_alloc = !!(flags & RPMALLOC_GROW_OR_FAIL);
- size_t usablesize = (ptr ? _rpmalloc_usable_size(ptr) : 0);
- if ((usablesize >= size) && !((uintptr_t)ptr & (alignment - 1))) {
- if (no_alloc || (size >= (usablesize / 2)))
- return ptr;
- }
- // Aligned alloc marks span as having aligned blocks
- void* block = (!no_alloc ? _rpmalloc_aligned_allocate(heap, alignment, size) : 0);
- if (EXPECTED(block != 0)) {
- if (!(flags & RPMALLOC_NO_PRESERVE) && ptr) {
- if (!oldsize)
- oldsize = usablesize;
- memcpy(block, ptr, oldsize < size ? oldsize : size);
- }
- _rpmalloc_deallocate(ptr);
- }
- return block;
-}
-
-
-////////////
-///
-/// Initialization, finalization and utility
-///
-//////
-
-//! Get the usable size of the given block
-static size_t
-_rpmalloc_usable_size(void* p) {
- //Grab the span using guaranteed span alignment
- span_t* span = (span_t*)((uintptr_t)p & _memory_span_mask);
- if (span->size_class < SIZE_CLASS_COUNT) {
- //Small/medium block
- void* blocks_start = pointer_offset(span, SPAN_HEADER_SIZE);
- return span->block_size - ((size_t)pointer_diff(p, blocks_start) % span->block_size);
- }
- if (span->size_class == SIZE_CLASS_LARGE) {
- //Large block
- size_t current_spans = span->span_count;
- return (current_spans * _memory_span_size) - (size_t)pointer_diff(p, span);
- }
- //Oversized block, page count is stored in span_count
- size_t current_pages = span->span_count;
- return (current_pages * _memory_page_size) - (size_t)pointer_diff(p, span);
-}
-
-//! Adjust and optimize the size class properties for the given class
-static void
-_rpmalloc_adjust_size_class(size_t iclass) {
- size_t block_size = _memory_size_class[iclass].block_size;
- size_t block_count = (_memory_span_size - SPAN_HEADER_SIZE) / block_size;
-
- _memory_size_class[iclass].block_count = (uint16_t)block_count;
- _memory_size_class[iclass].class_idx = (uint16_t)iclass;
-
- //Check if previous size classes can be merged
- if (iclass >= SMALL_CLASS_COUNT) {
- size_t prevclass = iclass;
- while (prevclass > 0) {
- --prevclass;
- //A class can be merged if number of pages and number of blocks are equal
- if (_memory_size_class[prevclass].block_count == _memory_size_class[iclass].block_count)
- _rpmalloc_memcpy_const(_memory_size_class + prevclass, _memory_size_class + iclass, sizeof(_memory_size_class[iclass]));
- else
- break;
- }
- }
-}
-
-//! Initialize the allocator and setup global data
-extern inline int
-rpmalloc_initialize(void) {
- if (_rpmalloc_initialized) {
- rpmalloc_thread_initialize();
- return 0;
- }
- return rpmalloc_initialize_config(0);
-}
-
-int
-rpmalloc_initialize_config(const rpmalloc_config_t * config) {
- if (_rpmalloc_initialized) {
- rpmalloc_thread_initialize();
- return 0;
- }
- _rpmalloc_initialized = 1;
-
- if (config)
- memcpy(&_memory_config, config, sizeof(rpmalloc_config_t));
- else
- _rpmalloc_memset_const(&_memory_config, 0, sizeof(rpmalloc_config_t));
-
- if (!_memory_config.memory_map || !_memory_config.memory_unmap) {
- _memory_config.memory_map = _rpmalloc_mmap_os;
- _memory_config.memory_unmap = _rpmalloc_unmap_os;
- }
-
-#if PLATFORM_WINDOWS
- SYSTEM_INFO system_info;
- memset(&system_info, 0, sizeof(system_info));
- GetSystemInfo(&system_info);
- _memory_map_granularity = system_info.dwAllocationGranularity;
-#else
- _memory_map_granularity = (size_t)sysconf(_SC_PAGESIZE);
-#endif
-
-#if RPMALLOC_CONFIGURABLE
- _memory_page_size = _memory_config.page_size;
-#else
- _memory_page_size = 0;
-#endif
- _memory_huge_pages = 0;
- if (!_memory_page_size) {
-#if PLATFORM_WINDOWS
- _memory_page_size = system_info.dwPageSize;
-#else
- _memory_page_size = _memory_map_granularity;
- if (_memory_config.enable_huge_pages) {
-#if defined(__linux__)
- size_t huge_page_size = 0;
- FILE* meminfo = fopen("/proc/meminfo", "r");
- if (meminfo) {
- char line[128];
- while (!huge_page_size && fgets(line, sizeof(line) - 1, meminfo)) {
- line[sizeof(line) - 1] = 0;
- if (strstr(line, "Hugepagesize:"))
- huge_page_size = (size_t)strtol(line + 13, 0, 10) * 1024;
- }
- fclose(meminfo);
- }
- if (huge_page_size) {
- _memory_huge_pages = 1;
- _memory_page_size = huge_page_size;
- _memory_map_granularity = huge_page_size;
- }
-#elif defined(__FreeBSD__)
- int rc;
- size_t sz = sizeof(rc);
-
- if (sysctlbyname("vm.pmap.pg_ps_enabled", &rc, &sz, NULL, 0) == 0 && rc == 1) {
- _memory_huge_pages = 1;
- _memory_page_size = 2 * 1024 * 1024;
- _memory_map_granularity = _memory_page_size;
- }
-#elif defined(__APPLE__) || defined(__NetBSD__)
- _memory_huge_pages = 1;
- _memory_page_size = 2 * 1024 * 1024;
- _memory_map_granularity = _memory_page_size;
-#endif
- }
-#endif
- }
- else {
- if (_memory_config.enable_huge_pages)
- _memory_huge_pages = 1;
- }
-
-#if PLATFORM_WINDOWS
- if (_memory_config.enable_huge_pages) {
- HANDLE token = 0;
- size_t large_page_minimum = GetLargePageMinimum();
- if (large_page_minimum)
- OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &token);
- if (token) {
- LUID luid;
- if (LookupPrivilegeValue(0, SE_LOCK_MEMORY_NAME, &luid)) {
- TOKEN_PRIVILEGES token_privileges;
- memset(&token_privileges, 0, sizeof(token_privileges));
- token_privileges.PrivilegeCount = 1;
- token_privileges.Privileges[0].Luid = luid;
- token_privileges.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
- if (AdjustTokenPrivileges(token, FALSE, &token_privileges, 0, 0, 0)) {
- if (GetLastError() == ERROR_SUCCESS)
- _memory_huge_pages = 1;
- }
- }
- CloseHandle(token);
- }
- if (_memory_huge_pages) {
- if (large_page_minimum > _memory_page_size)
- _memory_page_size = large_page_minimum;
- if (large_page_minimum > _memory_map_granularity)
- _memory_map_granularity = large_page_minimum;
- }
- }
-#endif
-
- size_t min_span_size = 256;
- size_t max_page_size;
-#if UINTPTR_MAX > 0xFFFFFFFF
- max_page_size = 4096ULL * 1024ULL * 1024ULL;
-#else
- max_page_size = 4 * 1024 * 1024;
-#endif
- if (_memory_page_size < min_span_size)
- _memory_page_size = min_span_size;
- if (_memory_page_size > max_page_size)
- _memory_page_size = max_page_size;
- _memory_page_size_shift = 0;
- size_t page_size_bit = _memory_page_size;
- while (page_size_bit != 1) {
- ++_memory_page_size_shift;
- page_size_bit >>= 1;
- }
- _memory_page_size = ((size_t)1 << _memory_page_size_shift);
-
-#if RPMALLOC_CONFIGURABLE
- if (!_memory_config.span_size) {
- _memory_span_size = _memory_default_span_size;
- _memory_span_size_shift = _memory_default_span_size_shift;
- _memory_span_mask = _memory_default_span_mask;
- }
- else {
- size_t span_size = _memory_config.span_size;
- if (span_size > (256 * 1024))
- span_size = (256 * 1024);
- _memory_span_size = 4096;
- _memory_span_size_shift = 12;
- while (_memory_span_size < span_size) {
- _memory_span_size <<= 1;
- ++_memory_span_size_shift;
- }
- _memory_span_mask = ~(uintptr_t)(_memory_span_size - 1);
- }
-#endif
-
- _memory_span_map_count = (_memory_config.span_map_count ? _memory_config.span_map_count : DEFAULT_SPAN_MAP_COUNT);
- if ((_memory_span_size * _memory_span_map_count) < _memory_page_size)
- _memory_span_map_count = (_memory_page_size / _memory_span_size);
- if ((_memory_page_size >= _memory_span_size) && ((_memory_span_map_count * _memory_span_size) % _memory_page_size))
- _memory_span_map_count = (_memory_page_size / _memory_span_size);
- _memory_heap_reserve_count = (_memory_span_map_count > DEFAULT_SPAN_MAP_COUNT) ? DEFAULT_SPAN_MAP_COUNT : _memory_span_map_count;
-
- _memory_config.page_size = _memory_page_size;
- _memory_config.span_size = _memory_span_size;
- _memory_config.span_map_count = _memory_span_map_count;
- _memory_config.enable_huge_pages = _memory_huge_pages;
-
-#if ((defined(__APPLE__) || defined(__HAIKU__)) && ENABLE_PRELOAD) || defined(__TINYC__)
- if (pthread_key_create(&_memory_thread_heap, _rpmalloc_heap_release_raw_fc))
- return -1;
-#endif
-#if defined(_WIN32) && (!defined(BUILD_DYNAMIC_LINK) || !BUILD_DYNAMIC_LINK)
- fls_key = FlsAlloc(&_rpmalloc_thread_destructor);
-#endif
-
- //Setup all small and medium size classes
- size_t iclass = 0;
- _memory_size_class[iclass].block_size = SMALL_GRANULARITY;
- _rpmalloc_adjust_size_class(iclass);
- for (iclass = 1; iclass < SMALL_CLASS_COUNT; ++iclass) {
- size_t size = iclass * SMALL_GRANULARITY;
- _memory_size_class[iclass].block_size = (uint32_t)size;
- _rpmalloc_adjust_size_class(iclass);
- }
- //At least two blocks per span, then fall back to large allocations
- _memory_medium_size_limit = (_memory_span_size - SPAN_HEADER_SIZE) >> 1;
- if (_memory_medium_size_limit > MEDIUM_SIZE_LIMIT)
- _memory_medium_size_limit = MEDIUM_SIZE_LIMIT;
- for (iclass = 0; iclass < MEDIUM_CLASS_COUNT; ++iclass) {
- size_t size = SMALL_SIZE_LIMIT + ((iclass + 1) * MEDIUM_GRANULARITY);
- if (size > _memory_medium_size_limit) {
- _memory_medium_size_limit = SMALL_SIZE_LIMIT + (iclass * MEDIUM_GRANULARITY);
- break;
- }
- _memory_size_class[SMALL_CLASS_COUNT + iclass].block_size = (uint32_t)size;
- _rpmalloc_adjust_size_class(SMALL_CLASS_COUNT + iclass);
- }
-
- _memory_orphan_heaps = 0;
-#if RPMALLOC_FIRST_CLASS_HEAPS
- _memory_first_class_orphan_heaps = 0;
-#endif
-#if ENABLE_STATISTICS
- atomic_store32(&_memory_active_heaps, 0);
- atomic_store32(&_mapped_pages, 0);
- _mapped_pages_peak = 0;
- atomic_store32(&_master_spans, 0);
- atomic_store32(&_mapped_total, 0);
- atomic_store32(&_unmapped_total, 0);
- atomic_store32(&_mapped_pages_os, 0);
- atomic_store32(&_huge_pages_current, 0);
- _huge_pages_peak = 0;
-#endif
- memset(_memory_heaps, 0, sizeof(_memory_heaps));
- atomic_store32_release(&_memory_global_lock, 0);
-
- rpmalloc_linker_reference();
-
- //Initialize this thread
- rpmalloc_thread_initialize();
- return 0;
-}
-
-//! Finalize the allocator
-void
-rpmalloc_finalize(void) {
- rpmalloc_thread_finalize(1);
- //rpmalloc_dump_statistics(stdout);
-
- if (_memory_global_reserve) {
- atomic_add32(&_memory_global_reserve_master->remaining_spans, -(int32_t)_memory_global_reserve_count);
- _memory_global_reserve_master = 0;
- _memory_global_reserve_count = 0;
- _memory_global_reserve = 0;
- }
- atomic_store32_release(&_memory_global_lock, 0);
-
- //Free all thread caches and fully free spans
- for (size_t list_idx = 0; list_idx < HEAP_ARRAY_SIZE; ++list_idx) {
- heap_t* heap = _memory_heaps[list_idx];
- while (heap) {
- heap_t* next_heap = heap->next_heap;
- heap->finalize = 1;
- _rpmalloc_heap_global_finalize(heap);
- heap = next_heap;
- }
- }
-
-#if ENABLE_GLOBAL_CACHE
- //Free global caches
- for (size_t iclass = 0; iclass < LARGE_CLASS_COUNT; ++iclass)
- _rpmalloc_global_cache_finalize(&_memory_span_cache[iclass]);
-#endif
-
-#if (defined(__APPLE__) || defined(__HAIKU__)) && ENABLE_PRELOAD
- pthread_key_delete(_memory_thread_heap);
-#endif
-#if defined(_WIN32) && (!defined(BUILD_DYNAMIC_LINK) || !BUILD_DYNAMIC_LINK)
- FlsFree(fls_key);
- fls_key = 0;
-#endif
-#if ENABLE_STATISTICS
- //If you hit these asserts you probably have memory leaks (perhaps global scope data doing dynamic allocations) or double frees in your code
- rpmalloc_assert(atomic_load32(&_mapped_pages) == 0, "Memory leak detected");
- rpmalloc_assert(atomic_load32(&_mapped_pages_os) == 0, "Memory leak detected");
-#endif
-
- _rpmalloc_initialized = 0;
-}
-
-//! Initialize thread, assign heap
-extern inline void
-rpmalloc_thread_initialize(void) {
- if (!get_thread_heap_raw()) {
- heap_t* heap = _rpmalloc_heap_allocate(0);
- if (heap) {
- _rpmalloc_stat_inc(&_memory_active_heaps);
- set_thread_heap(heap);
-#if defined(_WIN32) && (!defined(BUILD_DYNAMIC_LINK) || !BUILD_DYNAMIC_LINK)
- FlsSetValue(fls_key, heap);
-#endif
- }
- }
-}
-
-//! Finalize thread, orphan heap
-void
-rpmalloc_thread_finalize(int release_caches) {
- heap_t* heap = get_thread_heap_raw();
- if (heap)
- _rpmalloc_heap_release_raw(heap, release_caches);
- set_thread_heap(0);
-#if defined(_WIN32) && (!defined(BUILD_DYNAMIC_LINK) || !BUILD_DYNAMIC_LINK)
- FlsSetValue(fls_key, 0);
-#endif
-}
-
-int
-rpmalloc_is_thread_initialized(void) {
- return (get_thread_heap_raw() != 0) ? 1 : 0;
-}
-
-const rpmalloc_config_t*
-rpmalloc_config(void) {
- return &_memory_config;
-}
-
-// Extern interface
-
-extern inline RPMALLOC_ALLOCATOR void*
-rpmalloc(size_t size) {
-#if ENABLE_VALIDATE_ARGS
- if (size >= MAX_ALLOC_SIZE) {
- errno = EINVAL;
- return 0;
- }
-#endif
- heap_t* heap = get_thread_heap();
- return _rpmalloc_allocate(heap, size);
-}
-
-extern inline void
-rpfree(void* ptr) {
- _rpmalloc_deallocate(ptr);
-}
-
-extern inline RPMALLOC_ALLOCATOR void*
-rpcalloc(size_t num, size_t size) {
- size_t total;
-#if ENABLE_VALIDATE_ARGS
-#if PLATFORM_WINDOWS
- int err = SizeTMult(num, size, &total);
- if ((err != S_OK) || (total >= MAX_ALLOC_SIZE)) {
- errno = EINVAL;
- return 0;
- }
-#else
- int err = __builtin_umull_overflow(num, size, &total);
- if (err || (total >= MAX_ALLOC_SIZE)) {
- errno = EINVAL;
- return 0;
- }
-#endif
-#else
- total = num * size;
-#endif
- heap_t* heap = get_thread_heap();
- void* block = _rpmalloc_allocate(heap, total);
- if (block)
- memset(block, 0, total);
- return block;
-}
-
-extern inline RPMALLOC_ALLOCATOR void*
-rprealloc(void* ptr, size_t size) {
-#if ENABLE_VALIDATE_ARGS
- if (size >= MAX_ALLOC_SIZE) {
- errno = EINVAL;
- return ptr;
- }
-#endif
- heap_t* heap = get_thread_heap();
- return _rpmalloc_reallocate(heap, ptr, size, 0, 0);
-}
-
-extern RPMALLOC_ALLOCATOR void*
-rpaligned_realloc(void* ptr, size_t alignment, size_t size, size_t oldsize,
- unsigned int flags) {
-#if ENABLE_VALIDATE_ARGS
- if ((size + alignment < size) || (alignment > _memory_page_size)) {
- errno = EINVAL;
- return 0;
- }
-#endif
- heap_t* heap = get_thread_heap();
- return _rpmalloc_aligned_reallocate(heap, ptr, alignment, size, oldsize, flags);
-}
-
-extern RPMALLOC_ALLOCATOR void*
-rpaligned_alloc(size_t alignment, size_t size) {
- heap_t* heap = get_thread_heap();
- return _rpmalloc_aligned_allocate(heap, alignment, size);
-}
-
-extern inline RPMALLOC_ALLOCATOR void*
-rpaligned_calloc(size_t alignment, size_t num, size_t size) {
- size_t total;
-#if ENABLE_VALIDATE_ARGS
-#if PLATFORM_WINDOWS
- int err = SizeTMult(num, size, &total);
- if ((err != S_OK) || (total >= MAX_ALLOC_SIZE)) {
- errno = EINVAL;
- return 0;
- }
-#else
- int err = __builtin_umull_overflow(num, size, &total);
- if (err || (total >= MAX_ALLOC_SIZE)) {
- errno = EINVAL;
- return 0;
- }
-#endif
-#else
- total = num * size;
-#endif
- void* block = rpaligned_alloc(alignment, total);
- if (block)
- memset(block, 0, total);
- return block;
-}
-
-extern inline RPMALLOC_ALLOCATOR void*
-rpmemalign(size_t alignment, size_t size) {
- return rpaligned_alloc(alignment, size);
-}
-
-extern inline int
-rpposix_memalign(void** memptr, size_t alignment, size_t size) {
- if (memptr)
- *memptr = rpaligned_alloc(alignment, size);
- else
- return EINVAL;
- return *memptr ? 0 : ENOMEM;
-}
-
-extern inline size_t
-rpmalloc_usable_size(void* ptr) {
- return (ptr ? _rpmalloc_usable_size(ptr) : 0);
-}
-
-extern inline void
-rpmalloc_thread_collect(void) {
-}
-
-void
-rpmalloc_thread_statistics(rpmalloc_thread_statistics_t * stats) {
- memset(stats, 0, sizeof(rpmalloc_thread_statistics_t));
- heap_t* heap = get_thread_heap_raw();
- if (!heap)
- return;
-
- for (size_t iclass = 0; iclass < SIZE_CLASS_COUNT; ++iclass) {
- size_class_t* size_class = _memory_size_class + iclass;
- span_t* span = heap->size_class[iclass].partial_span;
- while (span) {
- size_t free_count = span->list_size;
- size_t block_count = size_class->block_count;
- if (span->free_list_limit < block_count)
- block_count = span->free_list_limit;
- free_count += (block_count - span->used_count);
- stats->sizecache += free_count * size_class->block_size;
- span = span->next;
- }
- }
-
-#if ENABLE_THREAD_CACHE
- for (size_t iclass = 0; iclass < LARGE_CLASS_COUNT; ++iclass) {
- span_cache_t* span_cache;
- if (!iclass)
- span_cache = &heap->span_cache;
- else
- span_cache = (span_cache_t*)(heap->span_large_cache + (iclass - 1));
- stats->spancache += span_cache->count * (iclass + 1) * _memory_span_size;
- }
-#endif
-
- span_t* deferred = (span_t*)atomic_load_ptr(&heap->span_free_deferred);
- while (deferred) {
- if (deferred->size_class != SIZE_CLASS_HUGE)
- stats->spancache += (size_t)deferred->span_count * _memory_span_size;
- deferred = (span_t*)deferred->free_list;
- }
-
-#if ENABLE_STATISTICS
- stats->thread_to_global = (size_t)atomic_load64(&heap->thread_to_global);
- stats->global_to_thread = (size_t)atomic_load64(&heap->global_to_thread);
-
- for (size_t iclass = 0; iclass < LARGE_CLASS_COUNT; ++iclass) {
- stats->span_use[iclass].current = (size_t)atomic_load32(&heap->span_use[iclass].current);
- stats->span_use[iclass].peak = (size_t)atomic_load32(&heap->span_use[iclass].high);
- stats->span_use[iclass].to_global = (size_t)atomic_load32(&heap->span_use[iclass].spans_to_global);
- stats->span_use[iclass].from_global = (size_t)atomic_load32(&heap->span_use[iclass].spans_from_global);
- stats->span_use[iclass].to_cache = (size_t)atomic_load32(&heap->span_use[iclass].spans_to_cache);
- stats->span_use[iclass].from_cache = (size_t)atomic_load32(&heap->span_use[iclass].spans_from_cache);
- stats->span_use[iclass].to_reserved = (size_t)atomic_load32(&heap->span_use[iclass].spans_to_reserved);
- stats->span_use[iclass].from_reserved = (size_t)atomic_load32(&heap->span_use[iclass].spans_from_reserved);
- stats->span_use[iclass].map_calls = (size_t)atomic_load32(&heap->span_use[iclass].spans_map_calls);
- }
- for (size_t iclass = 0; iclass < SIZE_CLASS_COUNT; ++iclass) {
- stats->size_use[iclass].alloc_current = (size_t)atomic_load32(&heap->size_class_use[iclass].alloc_current);
- stats->size_use[iclass].alloc_peak = (size_t)heap->size_class_use[iclass].alloc_peak;
- stats->size_use[iclass].alloc_total = (size_t)atomic_load32(&heap->size_class_use[iclass].alloc_total);
- stats->size_use[iclass].free_total = (size_t)atomic_load32(&heap->size_class_use[iclass].free_total);
- stats->size_use[iclass].spans_to_cache = (size_t)atomic_load32(&heap->size_class_use[iclass].spans_to_cache);
- stats->size_use[iclass].spans_from_cache = (size_t)atomic_load32(&heap->size_class_use[iclass].spans_from_cache);
- stats->size_use[iclass].spans_from_reserved = (size_t)atomic_load32(&heap->size_class_use[iclass].spans_from_reserved);
- stats->size_use[iclass].map_calls = (size_t)atomic_load32(&heap->size_class_use[iclass].spans_map_calls);
- }
-#endif
-}
-
-void
-rpmalloc_global_statistics(rpmalloc_global_statistics_t * stats) {
- memset(stats, 0, sizeof(rpmalloc_global_statistics_t));
-#if ENABLE_STATISTICS
- stats->mapped = (size_t)atomic_load32(&_mapped_pages) * _memory_page_size;
- stats->mapped_peak = (size_t)_mapped_pages_peak * _memory_page_size;
- stats->mapped_total = (size_t)atomic_load32(&_mapped_total) * _memory_page_size;
- stats->unmapped_total = (size_t)atomic_load32(&_unmapped_total) * _memory_page_size;
- stats->huge_alloc = (size_t)atomic_load32(&_huge_pages_current) * _memory_page_size;
- stats->huge_alloc_peak = (size_t)_huge_pages_peak * _memory_page_size;
-#endif
-#if ENABLE_GLOBAL_CACHE
- for (size_t iclass = 0; iclass < LARGE_CLASS_COUNT; ++iclass)
- stats->cached += _memory_span_cache[iclass].count * (iclass + 1) * _memory_span_size;
-#endif
-}
-
-#if ENABLE_STATISTICS
-
-static void
-_memory_heap_dump_statistics(heap_t * heap, void* file) {
- fprintf(file, "Heap %d stats:\n", heap->id);
- fprintf(file, "Class CurAlloc PeakAlloc TotAlloc TotFree BlkSize BlkCount SpansCur SpansPeak PeakAllocMiB ToCacheMiB FromCacheMiB FromReserveMiB MmapCalls\n");
- for (size_t iclass = 0; iclass < SIZE_CLASS_COUNT; ++iclass) {
- if (!atomic_load32(&heap->size_class_use[iclass].alloc_total))
- continue;
- fprintf(file, "%3u: %10u %10u %10u %10u %8u %8u %8d %9d %13zu %11zu %12zu %14zu %9u\n", (uint32_t)iclass,
- atomic_load32(&heap->size_class_use[iclass].alloc_current),
- heap->size_class_use[iclass].alloc_peak,
- atomic_load32(&heap->size_class_use[iclass].alloc_total),
- atomic_load32(&heap->size_class_use[iclass].free_total),
- _memory_size_class[iclass].block_size,
- _memory_size_class[iclass].block_count,
- atomic_load32(&heap->size_class_use[iclass].spans_current),
- heap->size_class_use[iclass].spans_peak,
- ((size_t)heap->size_class_use[iclass].alloc_peak * (size_t)_memory_size_class[iclass].block_size) / (size_t)(1024 * 1024),
- ((size_t)atomic_load32(&heap->size_class_use[iclass].spans_to_cache) * _memory_span_size) / (size_t)(1024 * 1024),
- ((size_t)atomic_load32(&heap->size_class_use[iclass].spans_from_cache) * _memory_span_size) / (size_t)(1024 * 1024),
- ((size_t)atomic_load32(&heap->size_class_use[iclass].spans_from_reserved) * _memory_span_size) / (size_t)(1024 * 1024),
- atomic_load32(&heap->size_class_use[iclass].spans_map_calls));
- }
- fprintf(file, "Spans Current Peak Deferred PeakMiB Cached ToCacheMiB FromCacheMiB ToReserveMiB FromReserveMiB ToGlobalMiB FromGlobalMiB MmapCalls\n");
- for (size_t iclass = 0; iclass < LARGE_CLASS_COUNT; ++iclass) {
- if (!atomic_load32(&heap->span_use[iclass].high) && !atomic_load32(&heap->span_use[iclass].spans_map_calls))
- continue;
- fprintf(file, "%4u: %8d %8u %8u %8zu %7u %11zu %12zu %12zu %14zu %11zu %13zu %10u\n", (uint32_t)(iclass + 1),
- atomic_load32(&heap->span_use[iclass].current),
- atomic_load32(&heap->span_use[iclass].high),
- atomic_load32(&heap->span_use[iclass].spans_deferred),
- ((size_t)atomic_load32(&heap->span_use[iclass].high) * (size_t)_memory_span_size * (iclass + 1)) / (size_t)(1024 * 1024),
-#if ENABLE_THREAD_CACHE
- (unsigned int)(!iclass ? heap->span_cache.count : heap->span_large_cache[iclass - 1].count),
- ((size_t)atomic_load32(&heap->span_use[iclass].spans_to_cache) * (iclass + 1) * _memory_span_size) / (size_t)(1024 * 1024),
- ((size_t)atomic_load32(&heap->span_use[iclass].spans_from_cache) * (iclass + 1) * _memory_span_size) / (size_t)(1024 * 1024),
-#else
- 0, (size_t)0, (size_t)0,
-#endif
- ((size_t)atomic_load32(&heap->span_use[iclass].spans_to_reserved) * (iclass + 1) * _memory_span_size) / (size_t)(1024 * 1024),
- ((size_t)atomic_load32(&heap->span_use[iclass].spans_from_reserved) * (iclass + 1) * _memory_span_size) / (size_t)(1024 * 1024),
- ((size_t)atomic_load32(&heap->span_use[iclass].spans_to_global) * (size_t)_memory_span_size * (iclass + 1)) / (size_t)(1024 * 1024),
- ((size_t)atomic_load32(&heap->span_use[iclass].spans_from_global) * (size_t)_memory_span_size * (iclass + 1)) / (size_t)(1024 * 1024),
- atomic_load32(&heap->span_use[iclass].spans_map_calls));
- }
- fprintf(file, "Full spans: %zu\n", heap->full_span_count);
- fprintf(file, "ThreadToGlobalMiB GlobalToThreadMiB\n");
- fprintf(file, "%17zu %17zu\n", (size_t)atomic_load64(&heap->thread_to_global) / (size_t)(1024 * 1024), (size_t)atomic_load64(&heap->global_to_thread) / (size_t)(1024 * 1024));
-}
-
-#endif
-
-void
-rpmalloc_dump_statistics(void* file) {
-#if ENABLE_STATISTICS
- for (size_t list_idx = 0; list_idx < HEAP_ARRAY_SIZE; ++list_idx) {
- heap_t* heap = _memory_heaps[list_idx];
- while (heap) {
- int need_dump = 0;
- for (size_t iclass = 0; !need_dump && (iclass < SIZE_CLASS_COUNT); ++iclass) {
- if (!atomic_load32(&heap->size_class_use[iclass].alloc_total)) {
- rpmalloc_assert(!atomic_load32(&heap->size_class_use[iclass].free_total), "Heap statistics counter mismatch");
- rpmalloc_assert(!atomic_load32(&heap->size_class_use[iclass].spans_map_calls), "Heap statistics counter mismatch");
- continue;
- }
- need_dump = 1;
- }
- for (size_t iclass = 0; !need_dump && (iclass < LARGE_CLASS_COUNT); ++iclass) {
- if (!atomic_load32(&heap->span_use[iclass].high) && !atomic_load32(&heap->span_use[iclass].spans_map_calls))
- continue;
- need_dump = 1;
- }
- if (need_dump)
- _memory_heap_dump_statistics(heap, file);
- heap = heap->next_heap;
- }
- }
- fprintf(file, "Global stats:\n");
- size_t huge_current = (size_t)atomic_load32(&_huge_pages_current) * _memory_page_size;
- size_t huge_peak = (size_t)_huge_pages_peak * _memory_page_size;
- fprintf(file, "HugeCurrentMiB HugePeakMiB\n");
- fprintf(file, "%14zu %11zu\n", huge_current / (size_t)(1024 * 1024), huge_peak / (size_t)(1024 * 1024));
-
- fprintf(file, "GlobalCacheMiB\n");
- for (size_t iclass = 0; iclass < LARGE_CLASS_COUNT; ++iclass) {
- global_cache_t* cache = _memory_span_cache + iclass;
- size_t global_cache = (size_t)cache->count * iclass * _memory_span_size;
-
- size_t global_overflow_cache = 0;
- span_t* span = cache->overflow;
- while (span) {
- global_overflow_cache += iclass * _memory_span_size;
- span = span->next;
- }
- if (global_cache || global_overflow_cache || cache->insert_count || cache->extract_count)
- fprintf(file, "%4zu: %8zuMiB (%8zuMiB overflow) %14zu insert %14zu extract\n", iclass + 1, global_cache / (size_t)(1024 * 1024), global_overflow_cache / (size_t)(1024 * 1024), cache->insert_count, cache->extract_count);
- }
-
- size_t mapped = (size_t)atomic_load32(&_mapped_pages) * _memory_page_size;
- size_t mapped_os = (size_t)atomic_load32(&_mapped_pages_os) * _memory_page_size;
- size_t mapped_peak = (size_t)_mapped_pages_peak * _memory_page_size;
- size_t mapped_total = (size_t)atomic_load32(&_mapped_total) * _memory_page_size;
- size_t unmapped_total = (size_t)atomic_load32(&_unmapped_total) * _memory_page_size;
- fprintf(file, "MappedMiB MappedOSMiB MappedPeakMiB MappedTotalMiB UnmappedTotalMiB\n");
- fprintf(file, "%9zu %11zu %13zu %14zu %16zu\n",
- mapped / (size_t)(1024 * 1024),
- mapped_os / (size_t)(1024 * 1024),
- mapped_peak / (size_t)(1024 * 1024),
- mapped_total / (size_t)(1024 * 1024),
- unmapped_total / (size_t)(1024 * 1024));
-
- fprintf(file, "\n");
-#if 0
- int64_t allocated = atomic_load64(&_allocation_counter);
- int64_t deallocated = atomic_load64(&_deallocation_counter);
- fprintf(file, "Allocation count: %lli\n", allocated);
- fprintf(file, "Deallocation count: %lli\n", deallocated);
- fprintf(file, "Current allocations: %lli\n", (allocated - deallocated));
- fprintf(file, "Master spans: %d\n", atomic_load32(&_master_spans));
- fprintf(file, "Dangling master spans: %d\n", atomic_load32(&_unmapped_master_spans));
-#endif
-#endif
- (void)sizeof(file);
-}
-
-#if RPMALLOC_FIRST_CLASS_HEAPS
-
-extern inline rpmalloc_heap_t*
-rpmalloc_heap_acquire(void) {
- // Must be a pristine heap from newly mapped memory pages, or else memory blocks
- // could already be allocated from the heap which would (wrongly) be released when
- // heap is cleared with rpmalloc_heap_free_all(). Also heaps guaranteed to be
- // pristine from the dedicated orphan list can be used.
- heap_t* heap = _rpmalloc_heap_allocate(1);
- rpmalloc_assume(heap != NULL);
- heap->owner_thread = 0;
- _rpmalloc_stat_inc(&_memory_active_heaps);
- return heap;
-}
-
-extern inline void
-rpmalloc_heap_release(rpmalloc_heap_t * heap) {
- if (heap)
- _rpmalloc_heap_release(heap, 1, 1);
-}
-
-extern inline RPMALLOC_ALLOCATOR void*
-rpmalloc_heap_alloc(rpmalloc_heap_t * heap, size_t size) {
-#if ENABLE_VALIDATE_ARGS
- if (size >= MAX_ALLOC_SIZE) {
- errno = EINVAL;
- return 0;
- }
-#endif
- return _rpmalloc_allocate(heap, size);
-}
-
-extern inline RPMALLOC_ALLOCATOR void*
-rpmalloc_heap_aligned_alloc(rpmalloc_heap_t * heap, size_t alignment, size_t size) {
-#if ENABLE_VALIDATE_ARGS
- if (size >= MAX_ALLOC_SIZE) {
- errno = EINVAL;
- return 0;
- }
-#endif
- return _rpmalloc_aligned_allocate(heap, alignment, size);
-}
-
-extern inline RPMALLOC_ALLOCATOR void*
-rpmalloc_heap_calloc(rpmalloc_heap_t * heap, size_t num, size_t size) {
- return rpmalloc_heap_aligned_calloc(heap, 0, num, size);
-}
-
-extern inline RPMALLOC_ALLOCATOR void*
-rpmalloc_heap_aligned_calloc(rpmalloc_heap_t * heap, size_t alignment, size_t num, size_t size) {
- size_t total;
-#if ENABLE_VALIDATE_ARGS
-#if PLATFORM_WINDOWS
- int err = SizeTMult(num, size, &total);
- if ((err != S_OK) || (total >= MAX_ALLOC_SIZE)) {
- errno = EINVAL;
- return 0;
- }
-#else
- int err = __builtin_umull_overflow(num, size, &total);
- if (err || (total >= MAX_ALLOC_SIZE)) {
- errno = EINVAL;
- return 0;
- }
-#endif
-#else
- total = num * size;
-#endif
- void* block = _rpmalloc_aligned_allocate(heap, alignment, total);
- if (block)
- memset(block, 0, total);
- return block;
-}
-
-extern inline RPMALLOC_ALLOCATOR void*
-rpmalloc_heap_realloc(rpmalloc_heap_t * heap, void* ptr, size_t size, unsigned int flags) {
-#if ENABLE_VALIDATE_ARGS
- if (size >= MAX_ALLOC_SIZE) {
- errno = EINVAL;
- return ptr;
- }
-#endif
- return _rpmalloc_reallocate(heap, ptr, size, 0, flags);
-}
-
-extern inline RPMALLOC_ALLOCATOR void*
-rpmalloc_heap_aligned_realloc(rpmalloc_heap_t * heap, void* ptr, size_t alignment, size_t size, unsigned int flags) {
-#if ENABLE_VALIDATE_ARGS
- if ((size + alignment < size) || (alignment > _memory_page_size)) {
- errno = EINVAL;
- return 0;
- }
-#endif
- return _rpmalloc_aligned_reallocate(heap, ptr, alignment, size, 0, flags);
-}
-
-extern inline void
-rpmalloc_heap_free(rpmalloc_heap_t * heap, void* ptr) {
- (void)sizeof(heap);
- _rpmalloc_deallocate(ptr);
-}
-
-extern inline void
-rpmalloc_heap_free_all(rpmalloc_heap_t * heap) {
- span_t* span;
- span_t* next_span;
-
- _rpmalloc_heap_cache_adopt_deferred(heap, 0);
-
- for (size_t iclass = 0; iclass < SIZE_CLASS_COUNT; ++iclass) {
- span = heap->size_class[iclass].partial_span;
- while (span) {
- next_span = span->next;
- _rpmalloc_heap_cache_insert(heap, span);
- span = next_span;
- }
- heap->size_class[iclass].partial_span = 0;
- span = heap->full_span[iclass];
- while (span) {
- next_span = span->next;
- _rpmalloc_heap_cache_insert(heap, span);
- span = next_span;
- }
- }
- memset(heap->size_class, 0, sizeof(heap->size_class));
- memset(heap->full_span, 0, sizeof(heap->full_span));
-
- span = heap->large_huge_span;
- while (span) {
- next_span = span->next;
- if (UNEXPECTED(span->size_class == SIZE_CLASS_HUGE))
- _rpmalloc_deallocate_huge(span);
- else
- _rpmalloc_heap_cache_insert(heap, span);
- span = next_span;
- }
- heap->large_huge_span = 0;
- heap->full_span_count = 0;
-
-#if ENABLE_THREAD_CACHE
- for (size_t iclass = 0; iclass < LARGE_CLASS_COUNT; ++iclass) {
- span_cache_t* span_cache;
- if (!iclass)
- span_cache = &heap->span_cache;
- else
- span_cache = (span_cache_t*)(heap->span_large_cache + (iclass - 1));
- if (!span_cache->count)
- continue;
-#if ENABLE_GLOBAL_CACHE
- _rpmalloc_stat_add64(&heap->thread_to_global, span_cache->count * (iclass + 1) * _memory_span_size);
- _rpmalloc_stat_add(&heap->span_use[iclass].spans_to_global, span_cache->count);
- _rpmalloc_global_cache_insert_spans(span_cache->span, iclass + 1, span_cache->count);
-#else
- for (size_t ispan = 0; ispan < span_cache->count; ++ispan)
- _rpmalloc_span_unmap(span_cache->span[ispan]);
-#endif
- span_cache->count = 0;
- }
-#endif
-
-#if ENABLE_STATISTICS
- for (size_t iclass = 0; iclass < SIZE_CLASS_COUNT; ++iclass) {
- atomic_store32(&heap->size_class_use[iclass].alloc_current, 0);
- atomic_store32(&heap->size_class_use[iclass].spans_current, 0);
- }
- for (size_t iclass = 0; iclass < LARGE_CLASS_COUNT; ++iclass) {
- atomic_store32(&heap->span_use[iclass].current, 0);
- }
-#endif
-}
-
-extern inline void
-rpmalloc_heap_thread_set_current(rpmalloc_heap_t * heap) {
- heap_t* prev_heap = get_thread_heap_raw();
- if (prev_heap != heap) {
- set_thread_heap(heap);
- if (prev_heap)
- rpmalloc_heap_release(prev_heap);
- }
-}
-
-#endif
-
-#if ENABLE_PRELOAD || ENABLE_OVERRIDE
-
-#include "malloc.c"
-
-#endif
-
-void
-rpmalloc_linker_reference(void) {
- (void)sizeof(_rpmalloc_initialized);
-}
diff --git a/lib/WinRpMalloc/src/rpmalloc.h b/lib/WinRpMalloc/src/rpmalloc.h
deleted file mode 100644
index 8e62b80..0000000
--- a/lib/WinRpMalloc/src/rpmalloc.h
+++ /dev/null
@@ -1,369 +0,0 @@
-/* rpmalloc.h - Memory allocator - Public Domain - 2016 Mattias Jansson
- *
- * This library provides a cross-platform lock free thread caching malloc implementation in C11.
- * The latest source code is always available at
- *
- * https://github.com/mjansson/rpmalloc
- *
- * This library is put in the public domain; you can redistribute it and/or modify it without any restrictions.
- *
- */
-
-#pragma once
-
-#include <stddef.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#if defined(__clang__) || defined(__GNUC__)
-# define RPMALLOC_EXPORT __attribute__((visibility("default")))
-# define RPMALLOC_ALLOCATOR
-# if (defined(__clang_major__) && (__clang_major__ < 4)) || (defined(__GNUC__) && defined(ENABLE_PRELOAD) && ENABLE_PRELOAD)
-# define RPMALLOC_ATTRIB_MALLOC
-# define RPMALLOC_ATTRIB_ALLOC_SIZE(size)
-# define RPMALLOC_ATTRIB_ALLOC_SIZE2(count, size)
-# else
-# define RPMALLOC_ATTRIB_MALLOC __attribute__((__malloc__))
-# define RPMALLOC_ATTRIB_ALLOC_SIZE(size) __attribute__((alloc_size(size)))
-# define RPMALLOC_ATTRIB_ALLOC_SIZE2(count, size) __attribute__((alloc_size(count, size)))
-# endif
-# define RPMALLOC_CDECL
-#elif defined(_MSC_VER)
-# define RPMALLOC_EXPORT
-# define RPMALLOC_ALLOCATOR __declspec(allocator) __declspec(restrict)
-# define RPMALLOC_ATTRIB_MALLOC
-# define RPMALLOC_ATTRIB_ALLOC_SIZE(size)
-# define RPMALLOC_ATTRIB_ALLOC_SIZE2(count,size)
-# define RPMALLOC_CDECL __cdecl
-#else
-# define RPMALLOC_EXPORT
-# define RPMALLOC_ALLOCATOR
-# define RPMALLOC_ATTRIB_MALLOC
-# define RPMALLOC_ATTRIB_ALLOC_SIZE(size)
-# define RPMALLOC_ATTRIB_ALLOC_SIZE2(count,size)
-# define RPMALLOC_CDECL
-#endif
-
- //! Define RPMALLOC_CONFIGURABLE to enable configuring sizes. Will introduce
- // a very small overhead due to some size calculations not being compile time constants
-#ifndef RPMALLOC_CONFIGURABLE
-#define RPMALLOC_CONFIGURABLE 0
-#endif
-
-//! Define RPMALLOC_FIRST_CLASS_HEAPS to enable heap based API (rpmalloc_heap_* functions).
-// Will introduce a very small overhead to track fully allocated spans in heaps
-#ifndef RPMALLOC_FIRST_CLASS_HEAPS
-#define RPMALLOC_FIRST_CLASS_HEAPS 0
-#endif
-
-//! Flag to rpaligned_realloc to not preserve content in reallocation
-#define RPMALLOC_NO_PRESERVE 1
-//! Flag to rpaligned_realloc to fail and return null pointer if grow cannot be done in-place,
-// in which case the original pointer is still valid (just like a call to realloc which failes to allocate
-// a new block).
-#define RPMALLOC_GROW_OR_FAIL 2
-
- typedef struct rpmalloc_global_statistics_t {
- //! Current amount of virtual memory mapped, all of which might not have been committed (only if ENABLE_STATISTICS=1)
- size_t mapped;
- //! Peak amount of virtual memory mapped, all of which might not have been committed (only if ENABLE_STATISTICS=1)
- size_t mapped_peak;
- //! Current amount of memory in global caches for small and medium sizes (<32KiB)
- size_t cached;
- //! Current amount of memory allocated in huge allocations, i.e larger than LARGE_SIZE_LIMIT which is 2MiB by default (only if ENABLE_STATISTICS=1)
- size_t huge_alloc;
- //! Peak amount of memory allocated in huge allocations, i.e larger than LARGE_SIZE_LIMIT which is 2MiB by default (only if ENABLE_STATISTICS=1)
- size_t huge_alloc_peak;
- //! Total amount of memory mapped since initialization (only if ENABLE_STATISTICS=1)
- size_t mapped_total;
- //! Total amount of memory unmapped since initialization (only if ENABLE_STATISTICS=1)
- size_t unmapped_total;
- } rpmalloc_global_statistics_t;
-
- typedef struct rpmalloc_thread_statistics_t {
- //! Current number of bytes available in thread size class caches for small and medium sizes (<32KiB)
- size_t sizecache;
- //! Current number of bytes available in thread span caches for small and medium sizes (<32KiB)
- size_t spancache;
- //! Total number of bytes transitioned from thread cache to global cache (only if ENABLE_STATISTICS=1)
- size_t thread_to_global;
- //! Total number of bytes transitioned from global cache to thread cache (only if ENABLE_STATISTICS=1)
- size_t global_to_thread;
- //! Per span count statistics (only if ENABLE_STATISTICS=1)
- struct {
- //! Currently used number of spans
- size_t current;
- //! High water mark of spans used
- size_t peak;
- //! Number of spans transitioned to global cache
- size_t to_global;
- //! Number of spans transitioned from global cache
- size_t from_global;
- //! Number of spans transitioned to thread cache
- size_t to_cache;
- //! Number of spans transitioned from thread cache
- size_t from_cache;
- //! Number of spans transitioned to reserved state
- size_t to_reserved;
- //! Number of spans transitioned from reserved state
- size_t from_reserved;
- //! Number of raw memory map calls (not hitting the reserve spans but resulting in actual OS mmap calls)
- size_t map_calls;
- } span_use[64];
- //! Per size class statistics (only if ENABLE_STATISTICS=1)
- struct {
- //! Current number of allocations
- size_t alloc_current;
- //! Peak number of allocations
- size_t alloc_peak;
- //! Total number of allocations
- size_t alloc_total;
- //! Total number of frees
- size_t free_total;
- //! Number of spans transitioned to cache
- size_t spans_to_cache;
- //! Number of spans transitioned from cache
- size_t spans_from_cache;
- //! Number of spans transitioned from reserved state
- size_t spans_from_reserved;
- //! Number of raw memory map calls (not hitting the reserve spans but resulting in actual OS mmap calls)
- size_t map_calls;
- } size_use[128];
- } rpmalloc_thread_statistics_t;
-
- typedef struct rpmalloc_config_t {
- //! Map memory pages for the given number of bytes. The returned address MUST be
- // aligned to the rpmalloc span size, which will always be a power of two.
- // Optionally the function can store an alignment offset in the offset variable
- // in case it performs alignment and the returned pointer is offset from the
- // actual start of the memory region due to this alignment. The alignment offset
- // will be passed to the memory unmap function. The alignment offset MUST NOT be
- // larger than 65535 (storable in an uint16_t), if it is you must use natural
- // alignment to shift it into 16 bits. If you set a memory_map function, you
- // must also set a memory_unmap function or else the default implementation will
- // be used for both. This function must be thread safe, it can be called by
- // multiple threads simultaneously.
- void* (*memory_map)(size_t size, size_t* offset);
- //! Unmap the memory pages starting at address and spanning the given number of bytes.
- // If release is set to non-zero, the unmap is for an entire span range as returned by
- // a previous call to memory_map and that the entire range should be released. The
- // release argument holds the size of the entire span range. If release is set to 0,
- // the unmap is a partial decommit of a subset of the mapped memory range.
- // If you set a memory_unmap function, you must also set a memory_map function or
- // else the default implementation will be used for both. This function must be thread
- // safe, it can be called by multiple threads simultaneously.
- void (*memory_unmap)(void* address, size_t size, size_t offset, size_t release);
- //! Called when an assert fails, if asserts are enabled. Will use the standard assert()
- // if this is not set.
- void (*error_callback)(const char* message);
- //! Called when a call to map memory pages fails (out of memory). If this callback is
- // not set or returns zero the library will return a null pointer in the allocation
- // call. If this callback returns non-zero the map call will be retried. The argument
- // passed is the number of bytes that was requested in the map call. Only used if
- // the default system memory map function is used (memory_map callback is not set).
- int (*map_fail_callback)(size_t size);
- //! Size of memory pages. The page size MUST be a power of two. All memory mapping
- // requests to memory_map will be made with size set to a multiple of the page size.
- // Used if RPMALLOC_CONFIGURABLE is defined to 1, otherwise system page size is used.
- size_t page_size;
- //! Size of a span of memory blocks. MUST be a power of two, and in [4096,262144]
- // range (unless 0 - set to 0 to use the default span size). Used if RPMALLOC_CONFIGURABLE
- // is defined to 1.
- size_t span_size;
- //! Number of spans to map at each request to map new virtual memory blocks. This can
- // be used to minimize the system call overhead at the cost of virtual memory address
- // space. The extra mapped pages will not be written until actually used, so physical
- // committed memory should not be affected in the default implementation. Will be
- // aligned to a multiple of spans that match memory page size in case of huge pages.
- size_t span_map_count;
- //! Enable use of large/huge pages. If this flag is set to non-zero and page size is
- // zero, the allocator will try to enable huge pages and auto detect the configuration.
- // If this is set to non-zero and page_size is also non-zero, the allocator will
- // assume huge pages have been configured and enabled prior to initializing the
- // allocator.
- // For Windows, see https://docs.microsoft.com/en-us/windows/desktop/memory/large-page-support
- // For Linux, see https://www.kernel.org/doc/Documentation/vm/hugetlbpage.txt
- int enable_huge_pages;
- //! Respectively allocated pages and huge allocated pages names for systems
- // supporting it to be able to distinguish among anonymous regions.
- const char* page_name;
- const char* huge_page_name;
- } rpmalloc_config_t;
-
- //! Initialize allocator with default configuration
- RPMALLOC_EXPORT int
- rpmalloc_initialize(void);
-
- //! Initialize allocator with given configuration
- RPMALLOC_EXPORT int
- rpmalloc_initialize_config(const rpmalloc_config_t* config);
-
- //! Get allocator configuration
- RPMALLOC_EXPORT const rpmalloc_config_t*
- rpmalloc_config(void);
-
- //! Finalize allocator
- RPMALLOC_EXPORT void
- rpmalloc_finalize(void);
-
- //! Initialize allocator for calling thread
- RPMALLOC_EXPORT void
- rpmalloc_thread_initialize(void);
-
- //! Finalize allocator for calling thread
- RPMALLOC_EXPORT void
- rpmalloc_thread_finalize(int release_caches);
-
- //! Perform deferred deallocations pending for the calling thread heap
- RPMALLOC_EXPORT void
- rpmalloc_thread_collect(void);
-
- //! Query if allocator is initialized for calling thread
- RPMALLOC_EXPORT int
- rpmalloc_is_thread_initialized(void);
-
- //! Get per-thread statistics
- RPMALLOC_EXPORT void
- rpmalloc_thread_statistics(rpmalloc_thread_statistics_t* stats);
-
- //! Get global statistics
- RPMALLOC_EXPORT void
- rpmalloc_global_statistics(rpmalloc_global_statistics_t* stats);
-
- //! Dump all statistics in human readable format to file (should be a FILE*)
- RPMALLOC_EXPORT void
- rpmalloc_dump_statistics(void* file);
-
- //! Allocate a memory block of at least the given size
- RPMALLOC_EXPORT RPMALLOC_ALLOCATOR void*
- rpmalloc(size_t size) RPMALLOC_ATTRIB_MALLOC RPMALLOC_ATTRIB_ALLOC_SIZE(1);
-
- //! Free the given memory block
- RPMALLOC_EXPORT void
- rpfree(void* ptr);
-
- //! Allocate a memory block of at least the given size and zero initialize it
- RPMALLOC_EXPORT RPMALLOC_ALLOCATOR void*
- rpcalloc(size_t num, size_t size) RPMALLOC_ATTRIB_MALLOC RPMALLOC_ATTRIB_ALLOC_SIZE2(1, 2);
-
- //! Reallocate the given block to at least the given size
- RPMALLOC_EXPORT RPMALLOC_ALLOCATOR void*
- rprealloc(void* ptr, size_t size) RPMALLOC_ATTRIB_MALLOC RPMALLOC_ATTRIB_ALLOC_SIZE(2);
-
- //! Reallocate the given block to at least the given size and alignment,
- // with optional control flags (see RPMALLOC_NO_PRESERVE).
- // Alignment must be a power of two and a multiple of sizeof(void*),
- // and should ideally be less than memory page size. A caveat of rpmalloc
- // internals is that this must also be strictly less than the span size (default 64KiB)
- RPMALLOC_EXPORT RPMALLOC_ALLOCATOR void*
- rpaligned_realloc(void* ptr, size_t alignment, size_t size, size_t oldsize, unsigned int flags) RPMALLOC_ATTRIB_MALLOC RPMALLOC_ATTRIB_ALLOC_SIZE(3);
-
- //! Allocate a memory block of at least the given size and alignment.
- // Alignment must be a power of two and a multiple of sizeof(void*),
- // and should ideally be less than memory page size. A caveat of rpmalloc
- // internals is that this must also be strictly less than the span size (default 64KiB)
- RPMALLOC_EXPORT RPMALLOC_ALLOCATOR void*
- rpaligned_alloc(size_t alignment, size_t size) RPMALLOC_ATTRIB_MALLOC RPMALLOC_ATTRIB_ALLOC_SIZE(2);
-
- //! Allocate a memory block of at least the given size and alignment, and zero initialize it.
- // Alignment must be a power of two and a multiple of sizeof(void*),
- // and should ideally be less than memory page size. A caveat of rpmalloc
- // internals is that this must also be strictly less than the span size (default 64KiB)
- RPMALLOC_EXPORT RPMALLOC_ALLOCATOR void*
- rpaligned_calloc(size_t alignment, size_t num, size_t size) RPMALLOC_ATTRIB_MALLOC RPMALLOC_ATTRIB_ALLOC_SIZE2(2, 3);
-
- //! Allocate a memory block of at least the given size and alignment.
- // Alignment must be a power of two and a multiple of sizeof(void*),
- // and should ideally be less than memory page size. A caveat of rpmalloc
- // internals is that this must also be strictly less than the span size (default 64KiB)
- RPMALLOC_EXPORT RPMALLOC_ALLOCATOR void*
- rpmemalign(size_t alignment, size_t size) RPMALLOC_ATTRIB_MALLOC RPMALLOC_ATTRIB_ALLOC_SIZE(2);
-
- //! Allocate a memory block of at least the given size and alignment.
- // Alignment must be a power of two and a multiple of sizeof(void*),
- // and should ideally be less than memory page size. A caveat of rpmalloc
- // internals is that this must also be strictly less than the span size (default 64KiB)
- RPMALLOC_EXPORT int
- rpposix_memalign(void** memptr, size_t alignment, size_t size);
-
- //! Query the usable size of the given memory block (from given pointer to the end of block)
- RPMALLOC_EXPORT size_t
- rpmalloc_usable_size(void* ptr);
-
- //! Dummy empty function for forcing linker symbol inclusion
- RPMALLOC_EXPORT void
- rpmalloc_linker_reference(void);
-
-#if RPMALLOC_FIRST_CLASS_HEAPS
-
- //! Heap type
- typedef struct heap_t rpmalloc_heap_t;
-
- //! Acquire a new heap. Will reuse existing released heaps or allocate memory for a new heap
- // if none available. Heap API is implemented with the strict assumption that only one single
- // thread will call heap functions for a given heap at any given time, no functions are thread safe.
- RPMALLOC_EXPORT rpmalloc_heap_t*
- rpmalloc_heap_acquire(void);
-
- //! Release a heap (does NOT free the memory allocated by the heap, use rpmalloc_heap_free_all before destroying the heap).
- // Releasing a heap will enable it to be reused by other threads. Safe to pass a null pointer.
- RPMALLOC_EXPORT void
- rpmalloc_heap_release(rpmalloc_heap_t* heap);
-
- //! Allocate a memory block of at least the given size using the given heap.
- RPMALLOC_EXPORT RPMALLOC_ALLOCATOR void*
- rpmalloc_heap_alloc(rpmalloc_heap_t* heap, size_t size) RPMALLOC_ATTRIB_MALLOC RPMALLOC_ATTRIB_ALLOC_SIZE(2);
-
- //! Allocate a memory block of at least the given size using the given heap. The returned
- // block will have the requested alignment. Alignment must be a power of two and a multiple of sizeof(void*),
- // and should ideally be less than memory page size. A caveat of rpmalloc
- // internals is that this must also be strictly less than the span size (default 64KiB).
- RPMALLOC_EXPORT RPMALLOC_ALLOCATOR void*
- rpmalloc_heap_aligned_alloc(rpmalloc_heap_t* heap, size_t alignment, size_t size) RPMALLOC_ATTRIB_MALLOC RPMALLOC_ATTRIB_ALLOC_SIZE(3);
-
- //! Allocate a memory block of at least the given size using the given heap and zero initialize it.
- RPMALLOC_EXPORT RPMALLOC_ALLOCATOR void*
- rpmalloc_heap_calloc(rpmalloc_heap_t* heap, size_t num, size_t size) RPMALLOC_ATTRIB_MALLOC RPMALLOC_ATTRIB_ALLOC_SIZE2(2, 3);
-
- //! Allocate a memory block of at least the given size using the given heap and zero initialize it. The returned
- // block will have the requested alignment. Alignment must either be zero, or a power of two and a multiple of sizeof(void*),
- // and should ideally be less than memory page size. A caveat of rpmalloc
- // internals is that this must also be strictly less than the span size (default 64KiB).
- RPMALLOC_EXPORT RPMALLOC_ALLOCATOR void*
- rpmalloc_heap_aligned_calloc(rpmalloc_heap_t* heap, size_t alignment, size_t num, size_t size) RPMALLOC_ATTRIB_MALLOC RPMALLOC_ATTRIB_ALLOC_SIZE2(2, 3);
-
- //! Reallocate the given block to at least the given size. The memory block MUST be allocated
- // by the same heap given to this function.
- RPMALLOC_EXPORT RPMALLOC_ALLOCATOR void*
- rpmalloc_heap_realloc(rpmalloc_heap_t* heap, void* ptr, size_t size, unsigned int flags) RPMALLOC_ATTRIB_MALLOC RPMALLOC_ATTRIB_ALLOC_SIZE(3);
-
- //! Reallocate the given block to at least the given size. The memory block MUST be allocated
- // by the same heap given to this function. The returned block will have the requested alignment.
- // Alignment must be either zero, or a power of two and a multiple of sizeof(void*), and should ideally be
- // less than memory page size. A caveat of rpmalloc internals is that this must also be strictly less than
- // the span size (default 64KiB).
- RPMALLOC_EXPORT RPMALLOC_ALLOCATOR void*
- rpmalloc_heap_aligned_realloc(rpmalloc_heap_t* heap, void* ptr, size_t alignment, size_t size, unsigned int flags) RPMALLOC_ATTRIB_MALLOC RPMALLOC_ATTRIB_ALLOC_SIZE(4);
-
- //! Free the given memory block from the given heap. The memory block MUST be allocated
- // by the same heap given to this function.
- RPMALLOC_EXPORT void
- rpmalloc_heap_free(rpmalloc_heap_t* heap, void* ptr);
-
- //! Free all memory allocated by the heap
- RPMALLOC_EXPORT void
- rpmalloc_heap_free_all(rpmalloc_heap_t* heap);
-
- //! Set the given heap as the current heap for the calling thread. A heap MUST only be current heap
- // for a single thread, a heap can never be shared between multiple threads. The previous
- // current heap for the calling thread is released to be reused by other threads.
- RPMALLOC_EXPORT void
- rpmalloc_heap_thread_set_current(rpmalloc_heap_t* heap);
-
-#endif
-
-#ifdef __cplusplus
-}
-#endif