summaryrefslogtreecommitdiff
path: root/source
diff options
context:
space:
mode:
authorEugen Wissner <belka@caraus.de>2016-10-04 18:19:48 +0200
committerEugen Wissner <belka@caraus.de>2016-10-04 18:19:48 +0200
commit698660c4c8818f16fce7909a6c41fbe66666abec (patch)
tree2d76223d74072aa26a834915edee90cf40a5203f /source
parentbe9181698a3f3f84accb6dc8ae5e1b4fd81a2b22 (diff)
downloadtanya-698660c4c8818f16fce7909a6c41fbe66666abec.tar.gz
Make allocators shared
Diffstat (limited to 'source')
-rw-r--r--source/tanya/container/buffer.d13
-rw-r--r--source/tanya/container/list.d9
-rw-r--r--source/tanya/container/queue.d5
-rw-r--r--source/tanya/container/vector.d13
-rw-r--r--source/tanya/crypto/cipher.d4
-rw-r--r--source/tanya/event/internal/epoll.d5
-rw-r--r--source/tanya/event/internal/selector.d1
-rw-r--r--source/tanya/event/loop.d8
-rw-r--r--source/tanya/event/transport.d6
-rw-r--r--source/tanya/event/watcher.d19
-rw-r--r--source/tanya/memory/allocator.d104
-rw-r--r--source/tanya/memory/package.d8
-rw-r--r--source/tanya/memory/ullocator.d813
-rw-r--r--source/tanya/random.d12
14 files changed, 538 insertions, 482 deletions
diff --git a/source/tanya/container/buffer.d b/source/tanya/container/buffer.d
index 3d7205b..999cff5 100644
--- a/source/tanya/container/buffer.d
+++ b/source/tanya/container/buffer.d
@@ -12,8 +12,6 @@ module tanya.container.buffer;
import tanya.memory;
-@nogc:
-
version (unittest)
{
private int fillBuffer(void* buffer,
@@ -42,7 +40,6 @@ version (unittest)
*/
interface Buffer
{
-@nogc:
/**
* Returns: The size of the internal buffer.
*/
@@ -74,7 +71,6 @@ interface Buffer
*/
class ReadBuffer : Buffer
{
-@nogc:
/// Internal buffer.
protected ubyte[] _buffer;
@@ -87,7 +83,7 @@ class ReadBuffer : Buffer
/// Size by which the buffer will grow.
protected immutable size_t blockSize;
- private Allocator allocator;
+ private shared Allocator allocator;
invariant
{
@@ -107,7 +103,7 @@ class ReadBuffer : Buffer
*/
this(size_t size = 8192,
size_t minAvailable = 1024,
- Allocator allocator = defaultAllocator)
+ shared Allocator allocator = defaultAllocator)
{
this.allocator = allocator;
this.minAvailable = minAvailable;
@@ -294,7 +290,6 @@ class ReadBuffer : Buffer
*/
class WriteBuffer : Buffer
{
-@nogc:
/// Internal buffer.
protected ubyte[] _buffer;
@@ -310,7 +305,7 @@ class WriteBuffer : Buffer
/// The position of the free area in the buffer.
protected size_t position;
- private Allocator allocator;
+ private shared Allocator allocator;
invariant
{
@@ -325,7 +320,7 @@ class WriteBuffer : Buffer
* will grow.
*/
this(size_t size = 8192,
- Allocator allocator = defaultAllocator)
+ shared Allocator allocator = defaultAllocator)
{
this.allocator = allocator;
blockSize = size;
diff --git a/source/tanya/container/list.d b/source/tanya/container/list.d
index e6e4ffc..e3bf25c 100644
--- a/source/tanya/container/list.d
+++ b/source/tanya/container/list.d
@@ -20,7 +20,6 @@ import tanya.memory;
*/
class SList(T)
{
-@nogc:
/**
* Creates a new $(D_PSYMBOL SList).
*
@@ -28,7 +27,7 @@ class SList(T)
* allocator = The allocator should be used for the element
* allocations.
*/
- this(Allocator allocator = defaultAllocator)
+ this(shared Allocator allocator = defaultAllocator)
{
this.allocator = allocator;
reset();
@@ -241,7 +240,7 @@ class SList(T)
* Params:
* dg = $(D_KEYWORD foreach) body.
*/
- int opApply(int delegate(ref size_t i, ref T) @nogc dg)
+ int opApply(int delegate(ref size_t i, ref T) dg)
{
int result;
size_t i;
@@ -280,7 +279,7 @@ class SList(T)
}
/// Ditto.
- int opApply(int delegate(ref T) @nogc dg)
+ int opApply(int delegate(ref T) dg)
{
int result;
@@ -389,7 +388,7 @@ class SList(T)
/// Current position in the list.
protected Entry* position;
- private Allocator allocator;
+ private shared Allocator allocator;
}
interface Stuff
diff --git a/source/tanya/container/queue.d b/source/tanya/container/queue.d
index 0890bcf..de28de2 100644
--- a/source/tanya/container/queue.d
+++ b/source/tanya/container/queue.d
@@ -20,7 +20,6 @@ import tanya.memory;
*/
class Queue(T)
{
-@nogc:
/**
* Creates a new $(D_PSYMBOL Queue).
*
@@ -28,7 +27,7 @@ class Queue(T)
* allocator = The allocator should be used for the element
* allocations.
*/
- this(Allocator allocator = defaultAllocator)
+ this(shared Allocator allocator = defaultAllocator)
{
this.allocator = allocator;
}
@@ -207,7 +206,7 @@ class Queue(T)
/// The last element of the list.
protected Entry* rear;
- private Allocator allocator;
+ private shared Allocator allocator;
}
///
diff --git a/source/tanya/container/vector.d b/source/tanya/container/vector.d
index 4f66dda..fb8353b 100644
--- a/source/tanya/container/vector.d
+++ b/source/tanya/container/vector.d
@@ -12,8 +12,6 @@ module tanya.container.vector;
import tanya.memory;
-@nogc:
-
/**
* One dimensional array. It allocates automatically if needed.
*
@@ -34,7 +32,6 @@ import tanya.memory;
*/
class Vector(T)
{
-@nogc:
/**
* Creates a new $(D_PSYMBOL Vector).
*
@@ -43,14 +40,14 @@ class Vector(T)
* allocator = The allocator should be used for the element
* allocations.
*/
- this(size_t length, Allocator allocator = defaultAllocator)
+ this(size_t length, shared Allocator allocator = defaultAllocator)
{
this.allocator = allocator;
vector = makeArray!T(allocator, length);
}
/// Ditto.
- this(Allocator allocator = defaultAllocator)
+ this(shared Allocator allocator = defaultAllocator)
{
this(0, allocator);
}
@@ -194,7 +191,7 @@ class Vector(T)
* Params:
* dg = $(D_KEYWORD foreach) body.
*/
- int opApply(int delegate(ref T) @nogc dg)
+ int opApply(int delegate(ref T) dg)
{
int result;
@@ -211,7 +208,7 @@ class Vector(T)
}
/// Ditto.
- int opApply(int delegate(ref size_t i, ref T) @nogc dg)
+ int opApply(int delegate(ref size_t i, ref T) dg)
{
int result;
@@ -408,7 +405,7 @@ class Vector(T)
/// Container.
protected T[] vector;
- private Allocator allocator;
+ private shared Allocator allocator;
}
///
diff --git a/source/tanya/crypto/cipher.d b/source/tanya/crypto/cipher.d
index 60d1587..d436feb 100644
--- a/source/tanya/crypto/cipher.d
+++ b/source/tanya/crypto/cipher.d
@@ -43,7 +43,7 @@ enum Mode
ubyte[] applyPadding(ref ubyte[] input,
in Mode mode,
in ushort blockSize,
- Allocator allocator = defaultAllocator)
+ shared Allocator allocator = defaultAllocator)
in
{
assert(blockSize > 0 && blockSize <= 256);
@@ -204,7 +204,7 @@ unittest
ref ubyte[] removePadding(ref ubyte[] input,
in Mode mode,
in ushort blockSize,
- Allocator allocator = defaultAllocator)
+ shared Allocator allocator = defaultAllocator)
in
{
assert(input.length != 0);
diff --git a/source/tanya/event/internal/epoll.d b/source/tanya/event/internal/epoll.d
index f4e99d9..0e76c3a 100644
--- a/source/tanya/event/internal/epoll.d
+++ b/source/tanya/event/internal/epoll.d
@@ -28,8 +28,6 @@ import core.sys.posix.netinet.in_;
import core.time;
import std.algorithm.comparison;
-@nogc:
-
extern (C) nothrow
{ // TODO: Make a pull request for Phobos to mark this extern functions as @nogc.
int epoll_create1(int __flags);
@@ -42,7 +40,6 @@ private enum maxEvents = 128;
class EpollLoop : Loop
{
-@nogc:
/**
* Initializes the loop.
*/
@@ -108,7 +105,7 @@ class EpollLoop : Loop
* protocolFactory = Protocol factory.
* socket = Socket.
*/
- protected override void acceptConnection(Protocol delegate() @nogc protocolFactory,
+ protected override void acceptConnection(Protocol delegate() protocolFactory,
int socket)
{
sockaddr_in client_addr;
diff --git a/source/tanya/event/internal/selector.d b/source/tanya/event/internal/selector.d
index 9682a5d..36dca76 100644
--- a/source/tanya/event/internal/selector.d
+++ b/source/tanya/event/internal/selector.d
@@ -24,7 +24,6 @@ import core.sys.posix.unistd;
*/
class SocketTransport : DuplexTransport
{
-@nogc:
private int socket_ = -1;
private Protocol protocol_;
diff --git a/source/tanya/event/loop.d b/source/tanya/event/loop.d
index 4383845..73b0557 100644
--- a/source/tanya/event/loop.d
+++ b/source/tanya/event/loop.d
@@ -29,8 +29,6 @@ static if (UseEpoll)
import tanya.event.internal.epoll;
}
-@nogc:
-
/**
* Events.
*/
@@ -49,7 +47,6 @@ alias EventMask = BitFlags!Event;
*/
abstract class Loop
{
-@nogc:
/// Pending watchers.
protected Queue!Watcher pendings;
@@ -204,7 +201,7 @@ abstract class Loop
* protocolFactory = Protocol factory.
* socket = Socket.
*/
- protected void acceptConnection(Protocol delegate() @nogc protocolFactory,
+ protected void acceptConnection(Protocol delegate() protocolFactory,
int socket);
/// Whether the event loop should be stopped.
@@ -219,7 +216,6 @@ abstract class Loop
*/
class BadLoopException : Exception
{
-@nogc:
/**
* Params:
* file = The file where the exception occurred.
@@ -227,7 +223,7 @@ class BadLoopException : Exception
* next = The previous exception in the chain of exceptions, if any.
*/
this(string file = __FILE__, size_t line = __LINE__, Throwable next = null)
- pure @safe nothrow const
+ pure @safe nothrow const @nogc
{
super("Event loop cannot be initialized.", file, line, next);
}
diff --git a/source/tanya/event/transport.d b/source/tanya/event/transport.d
index 7a3a60a..e1dc6f7 100644
--- a/source/tanya/event/transport.d
+++ b/source/tanya/event/transport.d
@@ -18,7 +18,6 @@ import tanya.event.protocol;
*/
class TransportException : Exception
{
-@nogc:
/**
* Params:
* msg = Message to output.
@@ -29,7 +28,7 @@ class TransportException : Exception
this(string msg,
string file = __FILE__,
size_t line = __LINE__,
- Throwable next = null) pure @safe nothrow const
+ Throwable next = null) pure @safe nothrow const @nogc
{
super(msg, file, line, next);
}
@@ -40,7 +39,6 @@ class TransportException : Exception
*/
interface Transport
{
-@nogc:
/**
* Returns: Protocol.
*/
@@ -78,7 +76,6 @@ interface Transport
*/
interface ReadTransport : Transport
{
-@nogc:
/**
* Returns: Underlying output buffer.
*/
@@ -103,7 +100,6 @@ interface ReadTransport : Transport
*/
interface WriteTransport : Transport
{
-@nogc:
/**
* Returns: Underlying input buffer.
*/
diff --git a/source/tanya/event/watcher.d b/source/tanya/event/watcher.d
index f0ed9e1..e19a21b 100644
--- a/source/tanya/event/watcher.d
+++ b/source/tanya/event/watcher.d
@@ -21,7 +21,6 @@ import std.functional;
*/
abstract class Watcher
{
-@nogc:
/// Whether the watcher is active.
bool active;
@@ -33,7 +32,6 @@ abstract class Watcher
class ConnectionWatcher : Watcher
{
-@nogc:
/// Watched file descriptor.
private int socket_;
@@ -41,7 +39,7 @@ class ConnectionWatcher : Watcher
protected Protocol delegate() protocolFactory;
/// Callback.
- package void delegate(Protocol delegate() @nogc protocolFactory,
+ package void delegate(Protocol delegate() protocolFactory,
int socket) accept;
invariant
@@ -54,27 +52,27 @@ class ConnectionWatcher : Watcher
* protocolFactory = Function returning a new $(D_PSYMBOL Protocol) instance.
* socket = Socket.
*/
- this(Protocol function() @nogc protocolFactory, int socket)
+ this(Protocol function() protocolFactory, int socket)
{
this.protocolFactory = toDelegate(protocolFactory);
socket_ = socket;
}
/// Ditto.
- this(Protocol delegate() @nogc protocolFactory, int socket)
+ this(Protocol delegate() protocolFactory, int socket)
{
this.protocolFactory = protocolFactory;
socket_ = socket;
}
/// Ditto.
- protected this(Protocol function() @nogc protocolFactory)
+ protected this(Protocol function() protocolFactory)
{
this.protocolFactory = toDelegate(protocolFactory);
}
/// Ditto.
- protected this(Protocol delegate() @nogc protocolFactory)
+ protected this(Protocol delegate() protocolFactory)
{
this.protocolFactory = protocolFactory;
}
@@ -90,7 +88,7 @@ class ConnectionWatcher : Watcher
/**
* Returns: Application protocol factory.
*/
- @property inout(Protocol delegate() @nogc) protocol() inout
+ @property inout(Protocol delegate()) protocol() inout
{
return protocolFactory;
}
@@ -107,7 +105,6 @@ class ConnectionWatcher : Watcher
*/
class IOWatcher : ConnectionWatcher
{
-@nogc:
/// References a watcher or a transport.
DuplexTransport transport_;
@@ -116,7 +113,7 @@ class IOWatcher : ConnectionWatcher
* protocolFactory = Function returning application specific protocol.
* transport = Transport.
*/
- this(Protocol delegate() @nogc protocolFactory,
+ this(Protocol delegate() protocolFactory,
DuplexTransport transport)
in
{
@@ -143,7 +140,7 @@ class IOWatcher : ConnectionWatcher
*
* Returns: $(D_KEYWORD this).
*/
- IOWatcher opCall(Protocol delegate() @nogc protocolFactory,
+ IOWatcher opCall(Protocol delegate() protocolFactory,
DuplexTransport transport) @safe pure nothrow
in
{
diff --git a/source/tanya/memory/allocator.d b/source/tanya/memory/allocator.d
index c206826..07a19b9 100644
--- a/source/tanya/memory/allocator.d
+++ b/source/tanya/memory/allocator.d
@@ -10,49 +10,75 @@
*/
module tanya.memory.allocator;
+import std.experimental.allocator;
+import std.traits;
+
/**
- * This interface should be similar to $(D_PSYMBOL
- * std.experimental.allocator.IAllocator), but usable in
- * $(D_KEYWORD @nogc)-code.
+ * Allocator interface.
*/
interface Allocator
{
-@nogc:
- /**
- * Allocates $(D_PARAM s) bytes of memory.
- *
- * Params:
- * s = Amount of memory to allocate.
- *
- * Returns: The pointer to the new allocated memory.
- */
- void[] allocate(size_t s) @safe;
+ /**
+ * Allocates $(D_PARAM size) bytes of memory.
+ *
+ * Params:
+ * size = Amount of memory to allocate.
+ *
+ * Returns: The pointer to the new allocated memory.
+ */
+ void[] allocate(size_t size) shared;
+
+ /**
+ * Deallocates a memory block.
+ *
+ * Params:
+ * p = A pointer to the memory block to be freed.
+ *
+ * Returns: Whether the deallocation was successful.
+ */
+ bool deallocate(void[] p) shared;
/**
- * Deallocates a memory block.
- *
- * Params:
- * p = A pointer to the memory block to be freed.
- *
- * Returns: Whether the deallocation was successful.
- */
- bool deallocate(void[] p) @safe;
-
- /**
- * Increases or decreases the size of a memory block.
- *
- * Params:
- * p = A pointer to the memory block.
- * size = Size of the reallocated block.
- *
- * Returns: Whether the reallocation was successful.
- */
- bool reallocate(ref void[] p, size_t s) @safe;
-
- /**
- * Static allocator instance and initializer.
- *
- * Returns: An $(D_PSYMBOL Allocator) instance.
- */
- static @property Allocator instance() @safe;
+ * Increases or decreases the size of a memory block.
+ *
+ * Params:
+ * p = A pointer to the memory block.
+ * size = Size of the reallocated block.
+ *
+ * Returns: Whether the reallocation was successful.
+ */
+ bool reallocate(ref void[] p, size_t size) shared;
+
+ /**
+ * Returns: The alignment offered.
+ */
+ @property immutable(uint) alignment() shared const @safe pure nothrow;
+}
+
+/**
+ * Params:
+ * T = Element type of the array being created.
+ * allocator = The allocator used for getting memory.
+ * array = A reference to the array being changed.
+ * length = New array length.
+ *
+ * Returns: $(D_KEYWORD true) upon success, $(D_KEYWORD false) if memory could
+ * not be reallocated. In the latter
+ */
+bool resizeArray(T)(shared Allocator allocator,
+ ref T[] array,
+ in size_t length)
+{
+ void[] buf = array;
+
+ if (!allocator.reallocate(buf, length * T.sizeof))
+ {
+ return false;
+ }
+ array = cast(T[]) buf;
+
+ return true;
}
+
+enum bool isFinalizable(T) = is(T == class) || is(T == interface)
+ || hasElaborateDestructor!T || isDynamicArray!T;
diff --git a/source/tanya/memory/package.d b/source/tanya/memory/package.d
index 67114df..4157fb2 100644
--- a/source/tanya/memory/package.d
+++ b/source/tanya/memory/package.d
@@ -26,8 +26,6 @@ else version (Posix)
import core.sys.posix.pthread;
}
-@nogc:
-
version (Windows)
{
package alias Mutex = CRITICAL_SECTION;
@@ -42,12 +40,12 @@ else version (Posix)
}
}
-@property void defaultAllocator(Allocator allocator) @safe nothrow
+@property void defaultAllocator(shared Allocator allocator) @safe nothrow
{
_defaultAllocator = allocator;
}
-@property Allocator defaultAllocator() @safe nothrow
+@property shared(Allocator) defaultAllocator() @safe nothrow
{
return _defaultAllocator;
}
@@ -204,4 +202,4 @@ bool resizeArray(T, A)(auto ref A allocator, ref T[] array, in size_t length)
enum bool isFinalizable(T) = is(T == class) || is(T == interface)
|| hasElaborateDestructor!T || isDynamicArray!T;
-private Allocator _defaultAllocator;
+private shared Allocator _defaultAllocator;
diff --git a/source/tanya/memory/ullocator.d b/source/tanya/memory/ullocator.d
index 54af6b4..43761f7 100644
--- a/source/tanya/memory/ullocator.d
+++ b/source/tanya/memory/ullocator.d
@@ -7,28 +7,33 @@
* License: $(LINK2 https://www.mozilla.org/en-US/MPL/2.0/,
* Mozilla Public License, v. 2.0).
* Authors: $(LINK2 mailto:info@caraus.de, Eugene Wissner)
- */
+ */
module tanya.memory.ullocator;
import tanya.memory.allocator;
+import core.atomic;
+import core.exception;
-@nogc:
-
-version (Posix):
-
-import core.sys.posix.sys.mman;
-import core.sys.posix.unistd;
+version (Posix)
+{
+ import core.stdc.errno;
+ import core.sys.posix.sys.mman;
+ import core.sys.posix.unistd;
+}
+else version (Windows)
+{
+ import core.sys.windows.winbase;
+ import core.sys.windows.windows;
+}
/**
- * Allocator for Posix systems with mmap/munmap support.
- *
* This allocator allocates memory in regions (multiple of 4 KB for example).
* Each region is then splitted in blocks. So it doesn't request the memory
* from the operating system on each call, but only if there are no large
- * enought free blocks in the available regions.
+ * enough free blocks in the available regions.
* Deallocation works in the same way. Deallocation doesn't immediately
* gives the memory back to the operating system, but marks the appropriate
- * block as free and only if all blocks in the region are free, the complet
+ * block as free and only if all blocks in the region are free, the complete
* region is deallocated.
*
* ----------------------------------------------------------------------------
@@ -42,382 +47,440 @@ import core.sys.posix.unistd;
* | N | -----------> next| || N | | |
* | | | | | || | | |
* --------------------------------------------------- ------------------------
+ *
+ * TODO:
+ * $(UL
+ * $(LI Thread safety (core.atomic.cas))
+ * $(LI If two neighbour blocks are free, they can be merged)
+ * $(LI Reallocation shoud check if there is enough free space in the
+ * next block instead of always moving the memory)
+ * $(LI Make 64 KB regions mininmal region size on Linux)
+ * )
*/
class Ullocator : Allocator
{
-@nogc:
- @disable this();
-
- shared static this() @safe nothrow
- {
- pageSize = sysconf(_SC_PAGE_SIZE);
- }
-
- /**
- * Allocates $(D_PARAM size) bytes of memory.
- *
- * Params:
- * size = Amount of memory to allocate.
- *
- * Returns: The pointer to the new allocated memory.
- */
- void[] allocate(size_t size) @trusted nothrow
+ @disable this();
+
+ shared static this()
{
- immutable dataSize = addAlignment(size);
+ version (Posix)
+ {
+ pageSize = sysconf(_SC_PAGE_SIZE);
+ }
+ else version (Windows)
+ {
+ SYSTEM_INFO si;
+ GetSystemInfo(&si);
+ pageSize = si.dwPageSize;
+ }
+ }
+
+ /**
+ * Allocates $(D_PARAM size) bytes of memory.
+ *
+ * Params:
+ * size = Amount of memory to allocate.
+ *
+ * Returns: The pointer to the new allocated memory.
+ */
+ void[] allocate(size_t size) shared @nogc @trusted nothrow
+ {
+ if (!size)
+ {
+ return null;
+ }
+ immutable dataSize = addAlignment(size);
+
+ void* data = findBlock(dataSize);
+ if (data is null)
+ {
+ data = initializeRegion(dataSize);
+ }
+
+ return data is null ? null : data[0..size];
+ }
+
+ ///
+ @nogc @safe nothrow unittest
+ {
+ auto p = Ullocator.instance.allocate(20);
+
+ assert(p);
+
+ Ullocator.instance.deallocate(p);
+ }
- void* data = findBlock(dataSize);
- if (data is null)
- {
- data = initializeRegion(dataSize);
- }
+ /**
+ * Search for a block large enough to keep $(D_PARAM size) and split it
+ * into two blocks if the block is too large.
+ *
+ * Params:
+ * size = Minimum size the block should have.
+ *
+ * Returns: Data the block points to or $(D_KEYWORD null).
+ */
+ private void* findBlock(size_t size) shared @nogc nothrow
+ {
+ Block block1;
+ RegionLoop: for (auto r = head; r !is null; r = r.next)
+ {
+ block1 = cast(Block) (cast(void*) r + regionEntrySize);
+ do
+ {
+ if (block1.free && block1.size >= size)
+ {
+ break RegionLoop;
+ }
+ }
+ while ((block1 = block1.next) !is null);
+ }
+ if (block1 is null)
+ {
+ return null;
+ }
+ else if (block1.size >= size + alignment + blockEntrySize)
+ { // Split the block if needed
+ Block block2 = cast(Block) (cast(void*) block1 + blockEntrySize + size);
+ block2.prev = block1;
+ if (block1.next is null)
+ {
+ block2.next = null;
+ }
+ else
+ {
+ block2.next = block1.next.next;
+ }
+ block1.next = block2;
+
+ block1.free = false;
+ block2.free = true;
+
+ block2.size = block1.size - blockEntrySize - size;
+ block1.size = size;
+
+ block2.region = block1.region;
+ atomicOp!"+="(block1.region.blocks, 1);
+ }
+ else
+ {
+ block1.free = false;
+ atomicOp!"+="(block1.region.blocks, 1);
+ }
+ return cast(void*) block1 + blockEntrySize;
+ }
- return data is null ? null : data[0..size];
+ /**
+ * Deallocates a memory block.
+ *
+ * Params:
+ * p = A pointer to the memory block to be freed.
+ *
+ * Returns: Whether the deallocation was successful.
+ */
+ bool deallocate(void[] p) shared @nogc @trusted nothrow
+ {
+ if (p is null)
+ {
+ return true;
+ }
+
+ Block block = cast(Block) (p.ptr - blockEntrySize);
+ if (block.region.blocks <= 1)
+ {
+ if (block.region.prev !is null)
+ {
+ block.region.prev.next = block.region.next;
+ }
+ else // Replace the list head. It is being deallocated
+ {
+ head = block.region.next;
+ }
+ if (block.region.next !is null)
+ {
+ block.region.next.prev = block.region.prev;
+ }
+ version (Posix)
+ {
+ return munmap(cast(void*) block.region, block.region.size) == 0;
+ }
+ version (Windows)
+ {
+ return VirtualFree(cast(void*) block.region, 0, MEM_RELEASE) == 0;
+ }
+ }
+ else
+ {
+ block.free = true;
+ atomicOp!"-="(block.region.blocks, 1);
+ return true;
+ }
}
- ///
- unittest
- {
- auto p = Ullocator.instance.allocate(20);
-
- assert(p);
-
- Ullocator.instance.deallocate(p);
- }
-
- /**
- * Search for a block large enough to keep $(D_PARAM size) and split it
- * into two blocks if the block is too large.
- *
- * Params:
- * size = Minimum size the block should have.
- *
- * Returns: Data the block points to or $(D_KEYWORD null).
- */
- private void* findBlock(size_t size) nothrow
- {
- Block block1;
- RegionLoop: for (auto r = head; r !is null; r = r.next)
- {
- block1 = cast(Block) (cast(void*) r + regionEntrySize);
- do
- {
- if (block1.free && block1.size >= size)
- {
- break RegionLoop;
- }
- }
- while ((block1 = block1.next) !is null);
- }
- if (block1 is null)
- {
- return null;
- }
- else if (block1.size >= size + alignment + blockEntrySize)
- { // Split the block if needed
- Block block2 = cast(Block) (cast(void*) block1 + blockEntrySize + size);
- block2.prev = block1;
- if (block1.next is null)
- {
- block2.next = null;
- }
- else
- {
- block2.next = block1.next.next;
- }
- block1.next = block2;
-
- block1.free = false;
- block2.free = true;
-
- block2.size = block1.size - blockEntrySize - size;
- block1.size = size;
-
- block2.region = block1.region;
- ++block1.region.blocks;
- }
- else
- {
- block1.free = false;
- ++block1.region.blocks;
- }
- return cast(void*) block1 + blockEntrySize;
- }
+ ///
+ @nogc @safe nothrow unittest
+ {
+ auto p = Ullocator.instance.allocate(20);
+
+ assert(Ullocator.instance.deallocate(p));
+ }
/**
- * Deallocates a memory block.
- *
- * Params:
- * p = A pointer to the memory block to be freed.
- *
- * Returns: Whether the deallocation was successful.
- */
- bool deallocate(void[] p) @trusted nothrow
+ * Increases or decreases the size of a memory block.
+ *
+ * Params:
+ * p = A pointer to the memory block.
+ * size = Size of the reallocated block.
+ *
+ * Returns: Whether the reallocation was successful.
+ */
+ bool reallocate(ref void[] p, size_t size) shared @nogc @trusted nothrow
{
- if (p is null)
- {
- return true;
- }
-
- Block block = cast(Block) (p.ptr - blockEntrySize);
- if (block.region.blocks <= 1)
- {
- if (block.region.prev !is null)
- {
- block.region.prev.next = block.region.next;
- }
- else // Replace the list head. It is being deallocated
- {
- head = block.region.next;
- }
- if (block.region.next !is null)
- {
- block.region.next.prev = block.region.prev;
- }
- return munmap(block.region, block.region.size) == 0;
- }
- else
- {
- block.free = true;
- --block.region.blocks;
- return true;
- }
+ void[] reallocP;
+
+ if (size == p.length)
+ {
+ return true;
+ }
+ else if (size > 0)
+ {
+ reallocP = allocate(size);
+ if (reallocP is null)
+ {
+ return false;
+ }
+ }
+
+ if (p !is null)
+ {
+ if (size > p.length)
+ {
+ reallocP[0..p.length] = p[0..$];
+ }
+ else if (size > 0)
+ {
+ reallocP[0..size] = p[0..size];
+ }
+ deallocate(p);
+ }
+ p = reallocP;
+
+ return true;
+ }
+
+ ///
+ @nogc @safe nothrow unittest
+ {
+ void[] p;
+ Ullocator.instance.reallocate(p, 10 * int.sizeof);
+ (cast(int[]) p)[7] = 123;
+
+ assert(p.length == 40);
+
+ Ullocator.instance.reallocate(p, 8 * int.sizeof);
+
+ assert(p.length == 32);
+ assert((cast(int[]) p)[7] == 123);
+
+ Ullocator.instance.reallocate(p, 20 * int.sizeof);
+ (cast(int[]) p)[15] = 8;
+
+ assert(p.length == 80);
+ assert((cast(int[]) p)[15] == 8);
+ assert((cast(int[]) p)[7] == 123);
+
+ Ullocator.instance.reallocate(p, 8 * int.sizeof);
+
+ assert(p.length == 32);
+ assert((cast(int[]) p)[7] == 123);
+
+ Ullocator.instance.deallocate(p);
}
- ///
- unittest
- {
- auto p = Ullocator.instance.allocate(20);
-
- assert(Ullocator.instance.deallocate(p));
- }
-
- /**
- * Increases or decreases the size of a memory block.
- *
- * Params:
- * p = A pointer to the memory block.
- * size = Size of the reallocated block.
- *
- * Returns: Whether the reallocation was successful.
- */
- bool reallocate(ref void[] p, size_t size) @trusted nothrow
- {
- if (size == p.length)
- {
- return true;
- }
-
- auto reallocP = allocate(size);
- if (reallocP is null)
- {
- return false;
- }
-
- if (p !is null)
- {
- if (size > p.length)
- {
- reallocP[0..p.length] = p[0..$];
- }
- else
- {
- reallocP[0..size] = p[0..size];
- }
- deallocate(p);
- }
- p = reallocP;
-
- return true;
- }
-
- ///
- unittest
- {
- void[] p;
- Ullocator.instance.reallocate(p, 10 * int.sizeof);
- (cast(int[]) p)[7] = 123;
-
- assert(p.length == 40);
-
- Ullocator.instance.reallocate(p, 8 * int.sizeof);
-
- assert(p.length == 32);
- assert((cast(int[]) p)[7] == 123);
-
- Ullocator.instance.reallocate(p, 20 * int.sizeof);
- (cast(int[]) p)[15] = 8;
-
- assert(p.length == 80);
- assert((cast(int[]) p)[15] == 8);
- assert((cast(int[]) p)[7] == 123);
-
- Ullocator.instance.reallocate(p, 8 * int.sizeof);
-
- assert(p.length == 32);
- assert((cast(int[]) p)[7] == 123);
-
- Ullocator.instance.deallocate(p);
- }
-
- /**
+ /**
* Static allocator instance and initializer.
- *
- * Returns: The global $(D_PSYMBOL Allocator) instance.
- */
- static @property Ullocator instance() @trusted nothrow
- {
- if (instance_ is null)
- {
- immutable instanceSize = addAlignment(__traits(classInstanceSize, Ullocator));
-
- Region head; // Will become soon our region list head
- void* data = initializeRegion(instanceSize, head);
-
- if (data is null)
- {
- return null;
- }
- data[0..instanceSize] = typeid(Ullocator).initializer[];
- instance_ = cast(Ullocator) data;
- instance_.head = head;
- }
- return instance_;
- }
-
- ///
- unittest
- {
- assert(instance is instance);
- }
-
- /**
- * Initializes a region for one element.
- *
- * Params:
- * size = Aligned size of the first data block in the region.
- * head = Region list head.
- *
- * Returns: A pointer to the data.
- */
- pragma(inline)
- private static void* initializeRegion(size_t size,
- ref Region head) nothrow
- {
- immutable regionSize = calculateRegionSize(size);
- void* p = mmap(null,
- regionSize,
- PROT_READ | PROT_WRITE,
- MAP_PRIVATE | MAP_ANON,
- -1,
- 0);
- if (p is MAP_FAILED)
- {
- return null;
- }
-
- Region region = cast(Region) p;
- region.blocks = 1;
- region.size = regionSize;
-
- // Set the pointer to the head of the region list
- if (head !is null)
- {
- head.prev = region;
- }
- region.next = head;
- region.prev = null;
- head = region;
-
- // Initialize the data block
- void* memoryPointer = p + regionEntrySize;
- Block block1 = cast(Block) memoryPointer;
- block1.size = size;
- block1.free = false;
-
- // It is what we want to return
- void* data = memoryPointer + blockEntrySize;
-
- // Free block after data
- memoryPointer = data + size;
- Block block2 = cast(Block) memoryPointer;
- block1.prev = block2.next = null;
- block1.next = block2;
- block2.prev = block1;
- block2.size = regionSize - size - regionEntrySize - blockEntrySize * 2;
- block2.free = true;
- block1.region = block2.region = region;
-
- return data;
- }
-
- /// Ditto.
- private void* initializeRegion(size_t size) nothrow
- {
- return initializeRegion(size, head);
- }
-
- /**
- * Params:
- * x = Space to be aligned.
- *
- * Returns: Aligned size of $(D_PARAM x).
- */
- pragma(inline)
- private static immutable(size_t) addAlignment(size_t x) @safe pure nothrow
- out (result)
- {
- assert(result > 0);
- }
- body
- {
- return (x - 1) / alignment * alignment + alignment;
- }
-
- /**
- * Params:
- * x = Required space.
- *
- * Returns: Minimum region size (a multiple of $(D_PSYMBOL pageSize)).
- */
- pragma(inline)
- private static immutable(size_t) calculateRegionSize(size_t x)
- @safe pure nothrow
- out (result)
- {
- assert(result > 0);
- }
- body
- {
- x += regionEntrySize + blockEntrySize * 2;
- return x / pageSize * pageSize + pageSize;
- }
-
- enum alignment = 8;
-
- private static Ullocator instance_;
-
- private shared static immutable long pageSize;
-
- private struct RegionEntry
- {
- Region prev;
- Region next;
- uint blocks;
- ulong size;
- }
- private alias Region = RegionEntry*;
- private enum regionEntrySize = 32;
-
- private Region head;
-
- private struct BlockEntry
- {
- Block prev;
- Block next;
- bool free;
- ulong size;
- Region region;
- }
- private alias Block = BlockEntry*;
- private enum blockEntrySize = 40;
+ *
+ * Returns: Global $(D_PSYMBOL Ullocator) instance.
+ */
+ static @property ref shared(Ullocator) instance() @nogc @trusted nothrow
+ {
+ if (instance_ is null)
+ {
+ immutable instanceSize = addAlignment(__traits(classInstanceSize, Ullocator));
+
+ Region head; // Will become soon our region list head
+ void* data = initializeRegion(instanceSize, head);
+ if (data !is null)
+ {
+ data[0..instanceSize] = typeid(Ullocator).initializer[];
+ instance_ = cast(shared Ullocator) data;
+ instance_.head = head;
+ }
+ }
+ return instance_;
+ }
+
+ ///
+ @nogc @safe nothrow unittest
+ {
+ assert(instance is instance);
+ }
+
+ /**
+ * Initializes a region for one element.
+ *
+ * Params:
+ * size = Aligned size of the first data block in the region.
+ * head = Region list head.
+ *
+ * Returns: A pointer to the data.
+ */
+ pragma(inline)
+ private static void* initializeRegion(size_t size,
+ ref Region head) @nogc nothrow
+ {
+ immutable regionSize = calculateRegionSize(size);
+
+ version (Posix)
+ {
+ void* p = mmap(null,
+ regionSize,
+ PROT_READ | PROT_WRITE,
+ MAP_PRIVATE | MAP_ANON,
+ -1,
+ 0);
+ if (p is MAP_FAILED)
+ {
+ if (errno == ENOMEM)
+ {
+ onOutOfMemoryError();
+ }
+ return null;
+ }
+ }
+ else version (Windows)
+ {
+ void* p = VirtualAlloc(null,
+ regionSize,
+ MEM_COMMIT,
+ PAGE_READWRITE);
+ if (p is null)
+ {
+ if (GetLastError() == ERROR_NOT_ENOUGH_MEMORY)
+ {
+ onOutOfMemoryError();
+ }
+ return null;
+ }
+ }
+
+ Region region = cast(Region) p;
+ region.blocks = 1;
+ region.size = regionSize;
+
+ // Set the pointer to the head of the region list
+ if (head !is null)
+ {
+ head.prev = region;
+ }
+ region.next = head;
+ region.prev = null;
+ head = region;
+
+ // Initialize the data block
+ void* memoryPointer = p + regionEntrySize;
+ Block block1 = cast(Block) memoryPointer;
+ block1.size = size;
+ block1.free = false;
+
+ // It is what we want to return
+ void* data = memoryPointer + blockEntrySize;
+
+ // Free block after data
+ memoryPointer = data + size;
+ Block block2 = cast(Block) memoryPointer;
+ block1.prev = block2.next = null;
+ block1.next = block2;
+ block2.prev = block1;
+ block2.size = regionSize - size - regionEntrySize - blockEntrySize * 2;
+ block2.free = true;
+ block1.region = block2.region = region;
+
+ return data;
+ }
+
+ /// Ditto.
+ private void* initializeRegion(size_t size) shared @nogc nothrow
+ {
+ return initializeRegion(size, head);
+ }
+
+ /**
+ * Params:
+ * x = Space to be aligned.
+ *
+ * Returns: Aligned size of $(D_PARAM x).
+ */
+ pragma(inline)
+ private static immutable(size_t) addAlignment(size_t x)
+ @nogc @safe pure nothrow
+ out (result)
+ {
+ assert(result > 0);
+ }
+ body
+ {
+ return (x - 1) / alignment_ * alignment_ + alignment_;
+ }
+
+ /**
+ * Params:
+ * x = Required space.
+ *
+ * Returns: Minimum region size (a multiple of $(D_PSYMBOL pageSize)).
+ */
+ pragma(inline)
+ private static immutable(size_t) calculateRegionSize(size_t x)
+ @nogc @safe pure nothrow
+ out (result)
+ {
+ assert(result > 0);
+ }
+ body
+ {
+ x += regionEntrySize + blockEntrySize * 2;
+ return x / pageSize * pageSize + pageSize;
+ }
+
+ @property immutable(uint) alignment() shared const @nogc @safe pure nothrow
+ {
+ return alignment_;
+ }
+ private enum alignment_ = 8;
+
+ private shared static Ullocator instance_;
+
+ private shared static immutable size_t pageSize;
+
+ private shared struct RegionEntry
+ {
+ Region prev;
+ Region next;
+ uint blocks;
+ size_t size;
+ }
+ private alias Region = shared RegionEntry*;
+ private enum regionEntrySize = 32;
+
+ private shared Region head;
+
+ private shared struct BlockEntry
+ {
+ Block prev;
+ Block next;
+ bool free;
+ size_t size;
+ Region region;
+ }
+ private alias Block = shared BlockEntry*;
+ private enum blockEntrySize = 40;
}
diff --git a/source/tanya/random.d b/source/tanya/random.d
index bf749c7..4e9197d 100644
--- a/source/tanya/random.d
+++ b/source/tanya/random.d
@@ -14,8 +14,6 @@ import tanya.memory;
import std.digest.sha;
import std.typecons;
-@nogc:
-
/// Block size of entropy accumulator (SHA-512).
enum blockSize = 64;
@@ -27,7 +25,6 @@ enum maxGather = 128;
*/
class EntropyException : Exception
{
-@nogc:
/**
* Params:
* msg = Message to output.
@@ -38,7 +35,7 @@ class EntropyException : Exception
this(string msg,
string file = __FILE__,
size_t line = __LINE__,
- Throwable next = null) pure @safe nothrow const
+ Throwable next = null) pure @safe nothrow const @nogc
{
super(msg, file, line, next);
}
@@ -49,7 +46,6 @@ class EntropyException : Exception
*/
abstract class EntropySource
{
-@nogc:
/// Amount of already generated entropy.
protected ushort size_;
@@ -103,7 +99,6 @@ version (linux)
*/
class PlatformEntropySource : EntropySource
{
- @nogc:
/**
* Returns: Minimum bytes required from the entropy source.
*/
@@ -164,13 +159,12 @@ version (linux)
*/
class Entropy
{
-@nogc:
/// Entropy sources.
protected EntropySource[] sources;
private ubyte sourceCount_;
- private Allocator allocator;
+ private shared Allocator allocator;
/// Entropy accumulator.
protected SHA!(maxGather * 8, 512) accumulator;
@@ -181,7 +175,7 @@ class Entropy
* allocator = Allocator to allocate entropy sources available on the
* system.
*/
- this(size_t maxSources = 20, Allocator allocator = defaultAllocator)
+ this(size_t maxSources = 20, shared Allocator allocator = defaultAllocator)
in
{
assert(maxSources > 0 && maxSources <= ubyte.max);