Make allocators shared
This commit is contained in:
parent
be9181698a
commit
698660c4c8
@ -12,8 +12,6 @@ module tanya.container.buffer;
|
|||||||
|
|
||||||
import tanya.memory;
|
import tanya.memory;
|
||||||
|
|
||||||
@nogc:
|
|
||||||
|
|
||||||
version (unittest)
|
version (unittest)
|
||||||
{
|
{
|
||||||
private int fillBuffer(void* buffer,
|
private int fillBuffer(void* buffer,
|
||||||
@ -42,7 +40,6 @@ version (unittest)
|
|||||||
*/
|
*/
|
||||||
interface Buffer
|
interface Buffer
|
||||||
{
|
{
|
||||||
@nogc:
|
|
||||||
/**
|
/**
|
||||||
* Returns: The size of the internal buffer.
|
* Returns: The size of the internal buffer.
|
||||||
*/
|
*/
|
||||||
@ -74,7 +71,6 @@ interface Buffer
|
|||||||
*/
|
*/
|
||||||
class ReadBuffer : Buffer
|
class ReadBuffer : Buffer
|
||||||
{
|
{
|
||||||
@nogc:
|
|
||||||
/// Internal buffer.
|
/// Internal buffer.
|
||||||
protected ubyte[] _buffer;
|
protected ubyte[] _buffer;
|
||||||
|
|
||||||
@ -87,7 +83,7 @@ class ReadBuffer : Buffer
|
|||||||
/// Size by which the buffer will grow.
|
/// Size by which the buffer will grow.
|
||||||
protected immutable size_t blockSize;
|
protected immutable size_t blockSize;
|
||||||
|
|
||||||
private Allocator allocator;
|
private shared Allocator allocator;
|
||||||
|
|
||||||
invariant
|
invariant
|
||||||
{
|
{
|
||||||
@ -107,7 +103,7 @@ class ReadBuffer : Buffer
|
|||||||
*/
|
*/
|
||||||
this(size_t size = 8192,
|
this(size_t size = 8192,
|
||||||
size_t minAvailable = 1024,
|
size_t minAvailable = 1024,
|
||||||
Allocator allocator = defaultAllocator)
|
shared Allocator allocator = defaultAllocator)
|
||||||
{
|
{
|
||||||
this.allocator = allocator;
|
this.allocator = allocator;
|
||||||
this.minAvailable = minAvailable;
|
this.minAvailable = minAvailable;
|
||||||
@ -294,7 +290,6 @@ class ReadBuffer : Buffer
|
|||||||
*/
|
*/
|
||||||
class WriteBuffer : Buffer
|
class WriteBuffer : Buffer
|
||||||
{
|
{
|
||||||
@nogc:
|
|
||||||
/// Internal buffer.
|
/// Internal buffer.
|
||||||
protected ubyte[] _buffer;
|
protected ubyte[] _buffer;
|
||||||
|
|
||||||
@ -310,7 +305,7 @@ class WriteBuffer : Buffer
|
|||||||
/// The position of the free area in the buffer.
|
/// The position of the free area in the buffer.
|
||||||
protected size_t position;
|
protected size_t position;
|
||||||
|
|
||||||
private Allocator allocator;
|
private shared Allocator allocator;
|
||||||
|
|
||||||
invariant
|
invariant
|
||||||
{
|
{
|
||||||
@ -325,7 +320,7 @@ class WriteBuffer : Buffer
|
|||||||
* will grow.
|
* will grow.
|
||||||
*/
|
*/
|
||||||
this(size_t size = 8192,
|
this(size_t size = 8192,
|
||||||
Allocator allocator = defaultAllocator)
|
shared Allocator allocator = defaultAllocator)
|
||||||
{
|
{
|
||||||
this.allocator = allocator;
|
this.allocator = allocator;
|
||||||
blockSize = size;
|
blockSize = size;
|
||||||
|
@ -20,7 +20,6 @@ import tanya.memory;
|
|||||||
*/
|
*/
|
||||||
class SList(T)
|
class SList(T)
|
||||||
{
|
{
|
||||||
@nogc:
|
|
||||||
/**
|
/**
|
||||||
* Creates a new $(D_PSYMBOL SList).
|
* Creates a new $(D_PSYMBOL SList).
|
||||||
*
|
*
|
||||||
@ -28,7 +27,7 @@ class SList(T)
|
|||||||
* allocator = The allocator should be used for the element
|
* allocator = The allocator should be used for the element
|
||||||
* allocations.
|
* allocations.
|
||||||
*/
|
*/
|
||||||
this(Allocator allocator = defaultAllocator)
|
this(shared Allocator allocator = defaultAllocator)
|
||||||
{
|
{
|
||||||
this.allocator = allocator;
|
this.allocator = allocator;
|
||||||
reset();
|
reset();
|
||||||
@ -241,7 +240,7 @@ class SList(T)
|
|||||||
* Params:
|
* Params:
|
||||||
* dg = $(D_KEYWORD foreach) body.
|
* 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;
|
int result;
|
||||||
size_t i;
|
size_t i;
|
||||||
@ -280,7 +279,7 @@ class SList(T)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Ditto.
|
/// Ditto.
|
||||||
int opApply(int delegate(ref T) @nogc dg)
|
int opApply(int delegate(ref T) dg)
|
||||||
{
|
{
|
||||||
int result;
|
int result;
|
||||||
|
|
||||||
@ -389,7 +388,7 @@ class SList(T)
|
|||||||
/// Current position in the list.
|
/// Current position in the list.
|
||||||
protected Entry* position;
|
protected Entry* position;
|
||||||
|
|
||||||
private Allocator allocator;
|
private shared Allocator allocator;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface Stuff
|
interface Stuff
|
||||||
|
@ -20,7 +20,6 @@ import tanya.memory;
|
|||||||
*/
|
*/
|
||||||
class Queue(T)
|
class Queue(T)
|
||||||
{
|
{
|
||||||
@nogc:
|
|
||||||
/**
|
/**
|
||||||
* Creates a new $(D_PSYMBOL Queue).
|
* Creates a new $(D_PSYMBOL Queue).
|
||||||
*
|
*
|
||||||
@ -28,7 +27,7 @@ class Queue(T)
|
|||||||
* allocator = The allocator should be used for the element
|
* allocator = The allocator should be used for the element
|
||||||
* allocations.
|
* allocations.
|
||||||
*/
|
*/
|
||||||
this(Allocator allocator = defaultAllocator)
|
this(shared Allocator allocator = defaultAllocator)
|
||||||
{
|
{
|
||||||
this.allocator = allocator;
|
this.allocator = allocator;
|
||||||
}
|
}
|
||||||
@ -207,7 +206,7 @@ class Queue(T)
|
|||||||
/// The last element of the list.
|
/// The last element of the list.
|
||||||
protected Entry* rear;
|
protected Entry* rear;
|
||||||
|
|
||||||
private Allocator allocator;
|
private shared Allocator allocator;
|
||||||
}
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
|
@ -12,8 +12,6 @@ module tanya.container.vector;
|
|||||||
|
|
||||||
import tanya.memory;
|
import tanya.memory;
|
||||||
|
|
||||||
@nogc:
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* One dimensional array. It allocates automatically if needed.
|
* One dimensional array. It allocates automatically if needed.
|
||||||
*
|
*
|
||||||
@ -34,7 +32,6 @@ import tanya.memory;
|
|||||||
*/
|
*/
|
||||||
class Vector(T)
|
class Vector(T)
|
||||||
{
|
{
|
||||||
@nogc:
|
|
||||||
/**
|
/**
|
||||||
* Creates a new $(D_PSYMBOL Vector).
|
* Creates a new $(D_PSYMBOL Vector).
|
||||||
*
|
*
|
||||||
@ -43,14 +40,14 @@ class Vector(T)
|
|||||||
* allocator = The allocator should be used for the element
|
* allocator = The allocator should be used for the element
|
||||||
* allocations.
|
* allocations.
|
||||||
*/
|
*/
|
||||||
this(size_t length, Allocator allocator = defaultAllocator)
|
this(size_t length, shared Allocator allocator = defaultAllocator)
|
||||||
{
|
{
|
||||||
this.allocator = allocator;
|
this.allocator = allocator;
|
||||||
vector = makeArray!T(allocator, length);
|
vector = makeArray!T(allocator, length);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Ditto.
|
/// Ditto.
|
||||||
this(Allocator allocator = defaultAllocator)
|
this(shared Allocator allocator = defaultAllocator)
|
||||||
{
|
{
|
||||||
this(0, allocator);
|
this(0, allocator);
|
||||||
}
|
}
|
||||||
@ -194,7 +191,7 @@ class Vector(T)
|
|||||||
* Params:
|
* Params:
|
||||||
* dg = $(D_KEYWORD foreach) body.
|
* dg = $(D_KEYWORD foreach) body.
|
||||||
*/
|
*/
|
||||||
int opApply(int delegate(ref T) @nogc dg)
|
int opApply(int delegate(ref T) dg)
|
||||||
{
|
{
|
||||||
int result;
|
int result;
|
||||||
|
|
||||||
@ -211,7 +208,7 @@ class Vector(T)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Ditto.
|
/// 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;
|
int result;
|
||||||
|
|
||||||
@ -408,7 +405,7 @@ class Vector(T)
|
|||||||
/// Container.
|
/// Container.
|
||||||
protected T[] vector;
|
protected T[] vector;
|
||||||
|
|
||||||
private Allocator allocator;
|
private shared Allocator allocator;
|
||||||
}
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
|
@ -43,7 +43,7 @@ enum Mode
|
|||||||
ubyte[] applyPadding(ref ubyte[] input,
|
ubyte[] applyPadding(ref ubyte[] input,
|
||||||
in Mode mode,
|
in Mode mode,
|
||||||
in ushort blockSize,
|
in ushort blockSize,
|
||||||
Allocator allocator = defaultAllocator)
|
shared Allocator allocator = defaultAllocator)
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
assert(blockSize > 0 && blockSize <= 256);
|
assert(blockSize > 0 && blockSize <= 256);
|
||||||
@ -204,7 +204,7 @@ unittest
|
|||||||
ref ubyte[] removePadding(ref ubyte[] input,
|
ref ubyte[] removePadding(ref ubyte[] input,
|
||||||
in Mode mode,
|
in Mode mode,
|
||||||
in ushort blockSize,
|
in ushort blockSize,
|
||||||
Allocator allocator = defaultAllocator)
|
shared Allocator allocator = defaultAllocator)
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
assert(input.length != 0);
|
assert(input.length != 0);
|
||||||
|
@ -28,8 +28,6 @@ import core.sys.posix.netinet.in_;
|
|||||||
import core.time;
|
import core.time;
|
||||||
import std.algorithm.comparison;
|
import std.algorithm.comparison;
|
||||||
|
|
||||||
@nogc:
|
|
||||||
|
|
||||||
extern (C) nothrow
|
extern (C) nothrow
|
||||||
{ // TODO: Make a pull request for Phobos to mark this extern functions as @nogc.
|
{ // TODO: Make a pull request for Phobos to mark this extern functions as @nogc.
|
||||||
int epoll_create1(int __flags);
|
int epoll_create1(int __flags);
|
||||||
@ -42,7 +40,6 @@ private enum maxEvents = 128;
|
|||||||
|
|
||||||
class EpollLoop : Loop
|
class EpollLoop : Loop
|
||||||
{
|
{
|
||||||
@nogc:
|
|
||||||
/**
|
/**
|
||||||
* Initializes the loop.
|
* Initializes the loop.
|
||||||
*/
|
*/
|
||||||
@ -108,7 +105,7 @@ class EpollLoop : Loop
|
|||||||
* protocolFactory = Protocol factory.
|
* protocolFactory = Protocol factory.
|
||||||
* socket = Socket.
|
* socket = Socket.
|
||||||
*/
|
*/
|
||||||
protected override void acceptConnection(Protocol delegate() @nogc protocolFactory,
|
protected override void acceptConnection(Protocol delegate() protocolFactory,
|
||||||
int socket)
|
int socket)
|
||||||
{
|
{
|
||||||
sockaddr_in client_addr;
|
sockaddr_in client_addr;
|
||||||
|
@ -24,7 +24,6 @@ import core.sys.posix.unistd;
|
|||||||
*/
|
*/
|
||||||
class SocketTransport : DuplexTransport
|
class SocketTransport : DuplexTransport
|
||||||
{
|
{
|
||||||
@nogc:
|
|
||||||
private int socket_ = -1;
|
private int socket_ = -1;
|
||||||
|
|
||||||
private Protocol protocol_;
|
private Protocol protocol_;
|
||||||
|
@ -29,8 +29,6 @@ static if (UseEpoll)
|
|||||||
import tanya.event.internal.epoll;
|
import tanya.event.internal.epoll;
|
||||||
}
|
}
|
||||||
|
|
||||||
@nogc:
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Events.
|
* Events.
|
||||||
*/
|
*/
|
||||||
@ -49,7 +47,6 @@ alias EventMask = BitFlags!Event;
|
|||||||
*/
|
*/
|
||||||
abstract class Loop
|
abstract class Loop
|
||||||
{
|
{
|
||||||
@nogc:
|
|
||||||
/// Pending watchers.
|
/// Pending watchers.
|
||||||
protected Queue!Watcher pendings;
|
protected Queue!Watcher pendings;
|
||||||
|
|
||||||
@ -204,7 +201,7 @@ abstract class Loop
|
|||||||
* protocolFactory = Protocol factory.
|
* protocolFactory = Protocol factory.
|
||||||
* socket = Socket.
|
* socket = Socket.
|
||||||
*/
|
*/
|
||||||
protected void acceptConnection(Protocol delegate() @nogc protocolFactory,
|
protected void acceptConnection(Protocol delegate() protocolFactory,
|
||||||
int socket);
|
int socket);
|
||||||
|
|
||||||
/// Whether the event loop should be stopped.
|
/// Whether the event loop should be stopped.
|
||||||
@ -219,7 +216,6 @@ abstract class Loop
|
|||||||
*/
|
*/
|
||||||
class BadLoopException : Exception
|
class BadLoopException : Exception
|
||||||
{
|
{
|
||||||
@nogc:
|
|
||||||
/**
|
/**
|
||||||
* Params:
|
* Params:
|
||||||
* file = The file where the exception occurred.
|
* 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.
|
* next = The previous exception in the chain of exceptions, if any.
|
||||||
*/
|
*/
|
||||||
this(string file = __FILE__, size_t line = __LINE__, Throwable next = null)
|
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);
|
super("Event loop cannot be initialized.", file, line, next);
|
||||||
}
|
}
|
||||||
|
@ -18,7 +18,6 @@ import tanya.event.protocol;
|
|||||||
*/
|
*/
|
||||||
class TransportException : Exception
|
class TransportException : Exception
|
||||||
{
|
{
|
||||||
@nogc:
|
|
||||||
/**
|
/**
|
||||||
* Params:
|
* Params:
|
||||||
* msg = Message to output.
|
* msg = Message to output.
|
||||||
@ -29,7 +28,7 @@ class TransportException : Exception
|
|||||||
this(string msg,
|
this(string msg,
|
||||||
string file = __FILE__,
|
string file = __FILE__,
|
||||||
size_t line = __LINE__,
|
size_t line = __LINE__,
|
||||||
Throwable next = null) pure @safe nothrow const
|
Throwable next = null) pure @safe nothrow const @nogc
|
||||||
{
|
{
|
||||||
super(msg, file, line, next);
|
super(msg, file, line, next);
|
||||||
}
|
}
|
||||||
@ -40,7 +39,6 @@ class TransportException : Exception
|
|||||||
*/
|
*/
|
||||||
interface Transport
|
interface Transport
|
||||||
{
|
{
|
||||||
@nogc:
|
|
||||||
/**
|
/**
|
||||||
* Returns: Protocol.
|
* Returns: Protocol.
|
||||||
*/
|
*/
|
||||||
@ -78,7 +76,6 @@ interface Transport
|
|||||||
*/
|
*/
|
||||||
interface ReadTransport : Transport
|
interface ReadTransport : Transport
|
||||||
{
|
{
|
||||||
@nogc:
|
|
||||||
/**
|
/**
|
||||||
* Returns: Underlying output buffer.
|
* Returns: Underlying output buffer.
|
||||||
*/
|
*/
|
||||||
@ -103,7 +100,6 @@ interface ReadTransport : Transport
|
|||||||
*/
|
*/
|
||||||
interface WriteTransport : Transport
|
interface WriteTransport : Transport
|
||||||
{
|
{
|
||||||
@nogc:
|
|
||||||
/**
|
/**
|
||||||
* Returns: Underlying input buffer.
|
* Returns: Underlying input buffer.
|
||||||
*/
|
*/
|
||||||
|
@ -21,7 +21,6 @@ import std.functional;
|
|||||||
*/
|
*/
|
||||||
abstract class Watcher
|
abstract class Watcher
|
||||||
{
|
{
|
||||||
@nogc:
|
|
||||||
/// Whether the watcher is active.
|
/// Whether the watcher is active.
|
||||||
bool active;
|
bool active;
|
||||||
|
|
||||||
@ -33,7 +32,6 @@ abstract class Watcher
|
|||||||
|
|
||||||
class ConnectionWatcher : Watcher
|
class ConnectionWatcher : Watcher
|
||||||
{
|
{
|
||||||
@nogc:
|
|
||||||
/// Watched file descriptor.
|
/// Watched file descriptor.
|
||||||
private int socket_;
|
private int socket_;
|
||||||
|
|
||||||
@ -41,7 +39,7 @@ class ConnectionWatcher : Watcher
|
|||||||
protected Protocol delegate() protocolFactory;
|
protected Protocol delegate() protocolFactory;
|
||||||
|
|
||||||
/// Callback.
|
/// Callback.
|
||||||
package void delegate(Protocol delegate() @nogc protocolFactory,
|
package void delegate(Protocol delegate() protocolFactory,
|
||||||
int socket) accept;
|
int socket) accept;
|
||||||
|
|
||||||
invariant
|
invariant
|
||||||
@ -54,27 +52,27 @@ class ConnectionWatcher : Watcher
|
|||||||
* protocolFactory = Function returning a new $(D_PSYMBOL Protocol) instance.
|
* protocolFactory = Function returning a new $(D_PSYMBOL Protocol) instance.
|
||||||
* socket = Socket.
|
* socket = Socket.
|
||||||
*/
|
*/
|
||||||
this(Protocol function() @nogc protocolFactory, int socket)
|
this(Protocol function() protocolFactory, int socket)
|
||||||
{
|
{
|
||||||
this.protocolFactory = toDelegate(protocolFactory);
|
this.protocolFactory = toDelegate(protocolFactory);
|
||||||
socket_ = socket;
|
socket_ = socket;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Ditto.
|
/// Ditto.
|
||||||
this(Protocol delegate() @nogc protocolFactory, int socket)
|
this(Protocol delegate() protocolFactory, int socket)
|
||||||
{
|
{
|
||||||
this.protocolFactory = protocolFactory;
|
this.protocolFactory = protocolFactory;
|
||||||
socket_ = socket;
|
socket_ = socket;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Ditto.
|
/// Ditto.
|
||||||
protected this(Protocol function() @nogc protocolFactory)
|
protected this(Protocol function() protocolFactory)
|
||||||
{
|
{
|
||||||
this.protocolFactory = toDelegate(protocolFactory);
|
this.protocolFactory = toDelegate(protocolFactory);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Ditto.
|
/// Ditto.
|
||||||
protected this(Protocol delegate() @nogc protocolFactory)
|
protected this(Protocol delegate() protocolFactory)
|
||||||
{
|
{
|
||||||
this.protocolFactory = protocolFactory;
|
this.protocolFactory = protocolFactory;
|
||||||
}
|
}
|
||||||
@ -90,7 +88,7 @@ class ConnectionWatcher : Watcher
|
|||||||
/**
|
/**
|
||||||
* Returns: Application protocol factory.
|
* Returns: Application protocol factory.
|
||||||
*/
|
*/
|
||||||
@property inout(Protocol delegate() @nogc) protocol() inout
|
@property inout(Protocol delegate()) protocol() inout
|
||||||
{
|
{
|
||||||
return protocolFactory;
|
return protocolFactory;
|
||||||
}
|
}
|
||||||
@ -107,7 +105,6 @@ class ConnectionWatcher : Watcher
|
|||||||
*/
|
*/
|
||||||
class IOWatcher : ConnectionWatcher
|
class IOWatcher : ConnectionWatcher
|
||||||
{
|
{
|
||||||
@nogc:
|
|
||||||
/// References a watcher or a transport.
|
/// References a watcher or a transport.
|
||||||
DuplexTransport transport_;
|
DuplexTransport transport_;
|
||||||
|
|
||||||
@ -116,7 +113,7 @@ class IOWatcher : ConnectionWatcher
|
|||||||
* protocolFactory = Function returning application specific protocol.
|
* protocolFactory = Function returning application specific protocol.
|
||||||
* transport = Transport.
|
* transport = Transport.
|
||||||
*/
|
*/
|
||||||
this(Protocol delegate() @nogc protocolFactory,
|
this(Protocol delegate() protocolFactory,
|
||||||
DuplexTransport transport)
|
DuplexTransport transport)
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
@ -143,7 +140,7 @@ class IOWatcher : ConnectionWatcher
|
|||||||
*
|
*
|
||||||
* Returns: $(D_KEYWORD this).
|
* Returns: $(D_KEYWORD this).
|
||||||
*/
|
*/
|
||||||
IOWatcher opCall(Protocol delegate() @nogc protocolFactory,
|
IOWatcher opCall(Protocol delegate() protocolFactory,
|
||||||
DuplexTransport transport) @safe pure nothrow
|
DuplexTransport transport) @safe pure nothrow
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
|
@ -10,49 +10,75 @@
|
|||||||
*/
|
*/
|
||||||
module tanya.memory.allocator;
|
module tanya.memory.allocator;
|
||||||
|
|
||||||
|
import std.experimental.allocator;
|
||||||
|
import std.traits;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This interface should be similar to $(D_PSYMBOL
|
* Allocator interface.
|
||||||
* std.experimental.allocator.IAllocator), but usable in
|
|
||||||
* $(D_KEYWORD @nogc)-code.
|
|
||||||
*/
|
*/
|
||||||
interface Allocator
|
interface Allocator
|
||||||
{
|
{
|
||||||
@nogc:
|
/**
|
||||||
/**
|
* Allocates $(D_PARAM size) bytes of memory.
|
||||||
* Allocates $(D_PARAM s) bytes of memory.
|
*
|
||||||
*
|
* Params:
|
||||||
* Params:
|
* size = Amount of memory to allocate.
|
||||||
* s = Amount of memory to allocate.
|
*
|
||||||
*
|
* Returns: The pointer to the new allocated memory.
|
||||||
* Returns: The pointer to the new allocated memory.
|
*/
|
||||||
*/
|
void[] allocate(size_t size) shared;
|
||||||
void[] allocate(size_t s) @safe;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Deallocates a memory block.
|
* Deallocates a memory block.
|
||||||
*
|
*
|
||||||
* Params:
|
* Params:
|
||||||
* p = A pointer to the memory block to be freed.
|
* p = A pointer to the memory block to be freed.
|
||||||
*
|
*
|
||||||
* Returns: Whether the deallocation was successful.
|
* Returns: Whether the deallocation was successful.
|
||||||
*/
|
*/
|
||||||
bool deallocate(void[] p) @safe;
|
bool deallocate(void[] p) shared;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Increases or decreases the size of a memory block.
|
* Increases or decreases the size of a memory block.
|
||||||
*
|
*
|
||||||
* Params:
|
* Params:
|
||||||
* p = A pointer to the memory block.
|
* p = A pointer to the memory block.
|
||||||
* size = Size of the reallocated block.
|
* size = Size of the reallocated block.
|
||||||
*
|
*
|
||||||
* Returns: Whether the reallocation was successful.
|
* Returns: Whether the reallocation was successful.
|
||||||
*/
|
*/
|
||||||
bool reallocate(ref void[] p, size_t s) @safe;
|
bool reallocate(ref void[] p, size_t size) shared;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Static allocator instance and initializer.
|
* Returns: The alignment offered.
|
||||||
*
|
*/
|
||||||
* Returns: An $(D_PSYMBOL Allocator) instance.
|
@property immutable(uint) alignment() shared const @safe pure nothrow;
|
||||||
*/
|
|
||||||
static @property Allocator instance() @safe;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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;
|
||||||
|
@ -26,8 +26,6 @@ else version (Posix)
|
|||||||
import core.sys.posix.pthread;
|
import core.sys.posix.pthread;
|
||||||
}
|
}
|
||||||
|
|
||||||
@nogc:
|
|
||||||
|
|
||||||
version (Windows)
|
version (Windows)
|
||||||
{
|
{
|
||||||
package alias Mutex = CRITICAL_SECTION;
|
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;
|
_defaultAllocator = allocator;
|
||||||
}
|
}
|
||||||
|
|
||||||
@property Allocator defaultAllocator() @safe nothrow
|
@property shared(Allocator) defaultAllocator() @safe nothrow
|
||||||
{
|
{
|
||||||
return _defaultAllocator;
|
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)
|
enum bool isFinalizable(T) = is(T == class) || is(T == interface)
|
||||||
|| hasElaborateDestructor!T || isDynamicArray!T;
|
|| hasElaborateDestructor!T || isDynamicArray!T;
|
||||||
|
|
||||||
private Allocator _defaultAllocator;
|
private shared Allocator _defaultAllocator;
|
||||||
|
@ -11,24 +11,29 @@
|
|||||||
module tanya.memory.ullocator;
|
module tanya.memory.ullocator;
|
||||||
|
|
||||||
import tanya.memory.allocator;
|
import tanya.memory.allocator;
|
||||||
|
import core.atomic;
|
||||||
|
import core.exception;
|
||||||
|
|
||||||
@nogc:
|
version (Posix)
|
||||||
|
{
|
||||||
version (Posix):
|
import core.stdc.errno;
|
||||||
|
import core.sys.posix.sys.mman;
|
||||||
import core.sys.posix.sys.mman;
|
import core.sys.posix.unistd;
|
||||||
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).
|
* 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
|
* 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
|
* 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
|
* Deallocation works in the same way. Deallocation doesn't immediately
|
||||||
* gives the memory back to the operating system, but marks the appropriate
|
* 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.
|
* region is deallocated.
|
||||||
*
|
*
|
||||||
* ----------------------------------------------------------------------------
|
* ----------------------------------------------------------------------------
|
||||||
@ -42,382 +47,440 @@ import core.sys.posix.unistd;
|
|||||||
* | N | -----------> next| || N | | |
|
* | 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
|
class Ullocator : Allocator
|
||||||
{
|
{
|
||||||
@nogc:
|
@disable this();
|
||||||
@disable this();
|
|
||||||
|
|
||||||
shared static this() @safe nothrow
|
shared static this()
|
||||||
{
|
|
||||||
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
|
|
||||||
{
|
{
|
||||||
immutable dataSize = addAlignment(size);
|
version (Posix)
|
||||||
|
{
|
||||||
void* data = findBlock(dataSize);
|
pageSize = sysconf(_SC_PAGE_SIZE);
|
||||||
if (data is null)
|
}
|
||||||
{
|
else version (Windows)
|
||||||
data = initializeRegion(dataSize);
|
{
|
||||||
}
|
SYSTEM_INFO si;
|
||||||
|
GetSystemInfo(&si);
|
||||||
return data is null ? null : data[0..size];
|
pageSize = si.dwPageSize;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
///
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Deallocates a memory block.
|
* Allocates $(D_PARAM size) bytes of memory.
|
||||||
*
|
*
|
||||||
* Params:
|
* Params:
|
||||||
* p = A pointer to the memory block to be freed.
|
* size = Amount of memory to allocate.
|
||||||
*
|
*
|
||||||
* Returns: Whether the deallocation was successful.
|
* Returns: The pointer to the new allocated memory.
|
||||||
*/
|
*/
|
||||||
bool deallocate(void[] p) @trusted nothrow
|
void[] allocate(size_t size) shared @nogc @trusted nothrow
|
||||||
{
|
{
|
||||||
if (p is null)
|
if (!size)
|
||||||
{
|
{
|
||||||
return true;
|
return null;
|
||||||
}
|
}
|
||||||
|
immutable dataSize = addAlignment(size);
|
||||||
|
|
||||||
Block block = cast(Block) (p.ptr - blockEntrySize);
|
void* data = findBlock(dataSize);
|
||||||
if (block.region.blocks <= 1)
|
if (data is null)
|
||||||
{
|
{
|
||||||
if (block.region.prev !is null)
|
data = initializeRegion(dataSize);
|
||||||
{
|
}
|
||||||
block.region.prev.next = block.region.next;
|
|
||||||
}
|
return data is null ? null : data[0..size];
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
unittest
|
@nogc @safe nothrow unittest
|
||||||
{
|
{
|
||||||
auto p = Ullocator.instance.allocate(20);
|
auto p = Ullocator.instance.allocate(20);
|
||||||
|
|
||||||
assert(Ullocator.instance.deallocate(p));
|
assert(p);
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
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)
|
* Search for a block large enough to keep $(D_PARAM size) and split it
|
||||||
{
|
* into two blocks if the block is too large.
|
||||||
return false;
|
*
|
||||||
}
|
* 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;
|
||||||
|
|
||||||
if (p !is null)
|
block1.free = false;
|
||||||
{
|
block2.free = true;
|
||||||
if (size > p.length)
|
|
||||||
{
|
|
||||||
reallocP[0..p.length] = p[0..$];
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
reallocP[0..size] = p[0..size];
|
|
||||||
}
|
|
||||||
deallocate(p);
|
|
||||||
}
|
|
||||||
p = reallocP;
|
|
||||||
|
|
||||||
return true;
|
block2.size = block1.size - blockEntrySize - size;
|
||||||
}
|
block1.size = size;
|
||||||
|
|
||||||
///
|
block2.region = block1.region;
|
||||||
unittest
|
atomicOp!"+="(block1.region.blocks, 1);
|
||||||
{
|
}
|
||||||
void[] p;
|
else
|
||||||
Ullocator.instance.reallocate(p, 10 * int.sizeof);
|
{
|
||||||
(cast(int[]) p)[7] = 123;
|
block1.free = false;
|
||||||
|
atomicOp!"+="(block1.region.blocks, 1);
|
||||||
|
}
|
||||||
|
return cast(void*) block1 + blockEntrySize;
|
||||||
|
}
|
||||||
|
|
||||||
assert(p.length == 40);
|
/**
|
||||||
|
* 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;
|
||||||
|
}
|
||||||
|
|
||||||
Ullocator.instance.reallocate(p, 8 * int.sizeof);
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
assert(p.length == 32);
|
///
|
||||||
assert((cast(int[]) p)[7] == 123);
|
@nogc @safe nothrow unittest
|
||||||
|
{
|
||||||
|
auto p = Ullocator.instance.allocate(20);
|
||||||
|
|
||||||
Ullocator.instance.reallocate(p, 20 * int.sizeof);
|
assert(Ullocator.instance.deallocate(p));
|
||||||
(cast(int[]) p)[15] = 8;
|
}
|
||||||
|
|
||||||
assert(p.length == 80);
|
/**
|
||||||
assert((cast(int[]) p)[15] == 8);
|
* Increases or decreases the size of a memory block.
|
||||||
assert((cast(int[]) p)[7] == 123);
|
*
|
||||||
|
* 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
|
||||||
|
{
|
||||||
|
void[] reallocP;
|
||||||
|
|
||||||
Ullocator.instance.reallocate(p, 8 * int.sizeof);
|
if (size == p.length)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else if (size > 0)
|
||||||
|
{
|
||||||
|
reallocP = allocate(size);
|
||||||
|
if (reallocP is null)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
assert(p.length == 32);
|
if (p !is null)
|
||||||
assert((cast(int[]) p)[7] == 123);
|
{
|
||||||
|
if (size > p.length)
|
||||||
|
{
|
||||||
|
reallocP[0..p.length] = p[0..$];
|
||||||
|
}
|
||||||
|
else if (size > 0)
|
||||||
|
{
|
||||||
|
reallocP[0..size] = p[0..size];
|
||||||
|
}
|
||||||
|
deallocate(p);
|
||||||
|
}
|
||||||
|
p = reallocP;
|
||||||
|
|
||||||
Ullocator.instance.deallocate(p);
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
* Static allocator instance and initializer.
|
* Static allocator instance and initializer.
|
||||||
*
|
*
|
||||||
* Returns: The global $(D_PSYMBOL Allocator) instance.
|
* Returns: Global $(D_PSYMBOL Ullocator) instance.
|
||||||
*/
|
*/
|
||||||
static @property Ullocator instance() @trusted nothrow
|
static @property ref shared(Ullocator) instance() @nogc @trusted nothrow
|
||||||
{
|
{
|
||||||
if (instance_ is null)
|
if (instance_ is null)
|
||||||
{
|
{
|
||||||
immutable instanceSize = addAlignment(__traits(classInstanceSize, Ullocator));
|
immutable instanceSize = addAlignment(__traits(classInstanceSize, Ullocator));
|
||||||
|
|
||||||
Region head; // Will become soon our region list head
|
Region head; // Will become soon our region list head
|
||||||
void* data = initializeRegion(instanceSize, 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_;
|
||||||
|
}
|
||||||
|
|
||||||
if (data is null)
|
///
|
||||||
{
|
@nogc @safe nothrow unittest
|
||||||
return null;
|
{
|
||||||
}
|
assert(instance is instance);
|
||||||
data[0..instanceSize] = typeid(Ullocator).initializer[];
|
}
|
||||||
instance_ = cast(Ullocator) data;
|
|
||||||
instance_.head = head;
|
|
||||||
}
|
|
||||||
return instance_;
|
|
||||||
}
|
|
||||||
|
|
||||||
///
|
/**
|
||||||
unittest
|
* Initializes a region for one element.
|
||||||
{
|
*
|
||||||
assert(instance is instance);
|
* 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)
|
||||||
* Initializes a region for one element.
|
{
|
||||||
*
|
void* p = mmap(null,
|
||||||
* Params:
|
regionSize,
|
||||||
* size = Aligned size of the first data block in the region.
|
PROT_READ | PROT_WRITE,
|
||||||
* head = Region list head.
|
MAP_PRIVATE | MAP_ANON,
|
||||||
*
|
-1,
|
||||||
* Returns: A pointer to the data.
|
0);
|
||||||
*/
|
if (p is MAP_FAILED)
|
||||||
pragma(inline)
|
{
|
||||||
private static void* initializeRegion(size_t size,
|
if (errno == ENOMEM)
|
||||||
ref Region head) nothrow
|
{
|
||||||
{
|
onOutOfMemoryError();
|
||||||
immutable regionSize = calculateRegionSize(size);
|
}
|
||||||
void* p = mmap(null,
|
return null;
|
||||||
regionSize,
|
}
|
||||||
PROT_READ | PROT_WRITE,
|
}
|
||||||
MAP_PRIVATE | MAP_ANON,
|
else version (Windows)
|
||||||
-1,
|
{
|
||||||
0);
|
void* p = VirtualAlloc(null,
|
||||||
if (p is MAP_FAILED)
|
regionSize,
|
||||||
{
|
MEM_COMMIT,
|
||||||
return null;
|
PAGE_READWRITE);
|
||||||
}
|
if (p is null)
|
||||||
|
{
|
||||||
|
if (GetLastError() == ERROR_NOT_ENOUGH_MEMORY)
|
||||||
|
{
|
||||||
|
onOutOfMemoryError();
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Region region = cast(Region) p;
|
Region region = cast(Region) p;
|
||||||
region.blocks = 1;
|
region.blocks = 1;
|
||||||
region.size = regionSize;
|
region.size = regionSize;
|
||||||
|
|
||||||
// Set the pointer to the head of the region list
|
// Set the pointer to the head of the region list
|
||||||
if (head !is null)
|
if (head !is null)
|
||||||
{
|
{
|
||||||
head.prev = region;
|
head.prev = region;
|
||||||
}
|
}
|
||||||
region.next = head;
|
region.next = head;
|
||||||
region.prev = null;
|
region.prev = null;
|
||||||
head = region;
|
head = region;
|
||||||
|
|
||||||
// Initialize the data block
|
// Initialize the data block
|
||||||
void* memoryPointer = p + regionEntrySize;
|
void* memoryPointer = p + regionEntrySize;
|
||||||
Block block1 = cast(Block) memoryPointer;
|
Block block1 = cast(Block) memoryPointer;
|
||||||
block1.size = size;
|
block1.size = size;
|
||||||
block1.free = false;
|
block1.free = false;
|
||||||
|
|
||||||
// It is what we want to return
|
// It is what we want to return
|
||||||
void* data = memoryPointer + blockEntrySize;
|
void* data = memoryPointer + blockEntrySize;
|
||||||
|
|
||||||
// Free block after data
|
// Free block after data
|
||||||
memoryPointer = data + size;
|
memoryPointer = data + size;
|
||||||
Block block2 = cast(Block) memoryPointer;
|
Block block2 = cast(Block) memoryPointer;
|
||||||
block1.prev = block2.next = null;
|
block1.prev = block2.next = null;
|
||||||
block1.next = block2;
|
block1.next = block2;
|
||||||
block2.prev = block1;
|
block2.prev = block1;
|
||||||
block2.size = regionSize - size - regionEntrySize - blockEntrySize * 2;
|
block2.size = regionSize - size - regionEntrySize - blockEntrySize * 2;
|
||||||
block2.free = true;
|
block2.free = true;
|
||||||
block1.region = block2.region = region;
|
block1.region = block2.region = region;
|
||||||
|
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Ditto.
|
/// Ditto.
|
||||||
private void* initializeRegion(size_t size) nothrow
|
private void* initializeRegion(size_t size) shared @nogc nothrow
|
||||||
{
|
{
|
||||||
return initializeRegion(size, head);
|
return initializeRegion(size, head);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Params:
|
* Params:
|
||||||
* x = Space to be aligned.
|
* x = Space to be aligned.
|
||||||
*
|
*
|
||||||
* Returns: Aligned size of $(D_PARAM x).
|
* Returns: Aligned size of $(D_PARAM x).
|
||||||
*/
|
*/
|
||||||
pragma(inline)
|
pragma(inline)
|
||||||
private static immutable(size_t) addAlignment(size_t x) @safe pure nothrow
|
private static immutable(size_t) addAlignment(size_t x)
|
||||||
out (result)
|
@nogc @safe pure nothrow
|
||||||
{
|
out (result)
|
||||||
assert(result > 0);
|
{
|
||||||
}
|
assert(result > 0);
|
||||||
body
|
}
|
||||||
{
|
body
|
||||||
return (x - 1) / alignment * alignment + alignment;
|
{
|
||||||
}
|
return (x - 1) / alignment_ * alignment_ + alignment_;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Params:
|
* Params:
|
||||||
* x = Required space.
|
* x = Required space.
|
||||||
*
|
*
|
||||||
* Returns: Minimum region size (a multiple of $(D_PSYMBOL pageSize)).
|
* Returns: Minimum region size (a multiple of $(D_PSYMBOL pageSize)).
|
||||||
*/
|
*/
|
||||||
pragma(inline)
|
pragma(inline)
|
||||||
private static immutable(size_t) calculateRegionSize(size_t x)
|
private static immutable(size_t) calculateRegionSize(size_t x)
|
||||||
@safe pure nothrow
|
@nogc @safe pure nothrow
|
||||||
out (result)
|
out (result)
|
||||||
{
|
{
|
||||||
assert(result > 0);
|
assert(result > 0);
|
||||||
}
|
}
|
||||||
body
|
body
|
||||||
{
|
{
|
||||||
x += regionEntrySize + blockEntrySize * 2;
|
x += regionEntrySize + blockEntrySize * 2;
|
||||||
return x / pageSize * pageSize + pageSize;
|
return x / pageSize * pageSize + pageSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
enum alignment = 8;
|
@property immutable(uint) alignment() shared const @nogc @safe pure nothrow
|
||||||
|
{
|
||||||
|
return alignment_;
|
||||||
|
}
|
||||||
|
private enum alignment_ = 8;
|
||||||
|
|
||||||
private static Ullocator instance_;
|
private shared static Ullocator instance_;
|
||||||
|
|
||||||
private shared static immutable long pageSize;
|
private shared static immutable size_t pageSize;
|
||||||
|
|
||||||
private struct RegionEntry
|
private shared struct RegionEntry
|
||||||
{
|
{
|
||||||
Region prev;
|
Region prev;
|
||||||
Region next;
|
Region next;
|
||||||
uint blocks;
|
uint blocks;
|
||||||
ulong size;
|
size_t size;
|
||||||
}
|
}
|
||||||
private alias Region = RegionEntry*;
|
private alias Region = shared RegionEntry*;
|
||||||
private enum regionEntrySize = 32;
|
private enum regionEntrySize = 32;
|
||||||
|
|
||||||
private Region head;
|
private shared Region head;
|
||||||
|
|
||||||
private struct BlockEntry
|
private shared struct BlockEntry
|
||||||
{
|
{
|
||||||
Block prev;
|
Block prev;
|
||||||
Block next;
|
Block next;
|
||||||
bool free;
|
bool free;
|
||||||
ulong size;
|
size_t size;
|
||||||
Region region;
|
Region region;
|
||||||
}
|
}
|
||||||
private alias Block = BlockEntry*;
|
private alias Block = shared BlockEntry*;
|
||||||
private enum blockEntrySize = 40;
|
private enum blockEntrySize = 40;
|
||||||
}
|
}
|
||||||
|
@ -14,8 +14,6 @@ import tanya.memory;
|
|||||||
import std.digest.sha;
|
import std.digest.sha;
|
||||||
import std.typecons;
|
import std.typecons;
|
||||||
|
|
||||||
@nogc:
|
|
||||||
|
|
||||||
/// Block size of entropy accumulator (SHA-512).
|
/// Block size of entropy accumulator (SHA-512).
|
||||||
enum blockSize = 64;
|
enum blockSize = 64;
|
||||||
|
|
||||||
@ -27,7 +25,6 @@ enum maxGather = 128;
|
|||||||
*/
|
*/
|
||||||
class EntropyException : Exception
|
class EntropyException : Exception
|
||||||
{
|
{
|
||||||
@nogc:
|
|
||||||
/**
|
/**
|
||||||
* Params:
|
* Params:
|
||||||
* msg = Message to output.
|
* msg = Message to output.
|
||||||
@ -38,7 +35,7 @@ class EntropyException : Exception
|
|||||||
this(string msg,
|
this(string msg,
|
||||||
string file = __FILE__,
|
string file = __FILE__,
|
||||||
size_t line = __LINE__,
|
size_t line = __LINE__,
|
||||||
Throwable next = null) pure @safe nothrow const
|
Throwable next = null) pure @safe nothrow const @nogc
|
||||||
{
|
{
|
||||||
super(msg, file, line, next);
|
super(msg, file, line, next);
|
||||||
}
|
}
|
||||||
@ -49,7 +46,6 @@ class EntropyException : Exception
|
|||||||
*/
|
*/
|
||||||
abstract class EntropySource
|
abstract class EntropySource
|
||||||
{
|
{
|
||||||
@nogc:
|
|
||||||
/// Amount of already generated entropy.
|
/// Amount of already generated entropy.
|
||||||
protected ushort size_;
|
protected ushort size_;
|
||||||
|
|
||||||
@ -103,7 +99,6 @@ version (linux)
|
|||||||
*/
|
*/
|
||||||
class PlatformEntropySource : EntropySource
|
class PlatformEntropySource : EntropySource
|
||||||
{
|
{
|
||||||
@nogc:
|
|
||||||
/**
|
/**
|
||||||
* Returns: Minimum bytes required from the entropy source.
|
* Returns: Minimum bytes required from the entropy source.
|
||||||
*/
|
*/
|
||||||
@ -164,13 +159,12 @@ version (linux)
|
|||||||
*/
|
*/
|
||||||
class Entropy
|
class Entropy
|
||||||
{
|
{
|
||||||
@nogc:
|
|
||||||
/// Entropy sources.
|
/// Entropy sources.
|
||||||
protected EntropySource[] sources;
|
protected EntropySource[] sources;
|
||||||
|
|
||||||
private ubyte sourceCount_;
|
private ubyte sourceCount_;
|
||||||
|
|
||||||
private Allocator allocator;
|
private shared Allocator allocator;
|
||||||
|
|
||||||
/// Entropy accumulator.
|
/// Entropy accumulator.
|
||||||
protected SHA!(maxGather * 8, 512) accumulator;
|
protected SHA!(maxGather * 8, 512) accumulator;
|
||||||
@ -181,7 +175,7 @@ class Entropy
|
|||||||
* allocator = Allocator to allocate entropy sources available on the
|
* allocator = Allocator to allocate entropy sources available on the
|
||||||
* system.
|
* system.
|
||||||
*/
|
*/
|
||||||
this(size_t maxSources = 20, Allocator allocator = defaultAllocator)
|
this(size_t maxSources = 20, shared Allocator allocator = defaultAllocator)
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
assert(maxSources > 0 && maxSources <= ubyte.max);
|
assert(maxSources > 0 && maxSources <= ubyte.max);
|
||||||
|
Loading…
Reference in New Issue
Block a user