Add userData!T properties for all descriptor based primitives.

This commit is contained in:
Sönke Ludwig 2018-03-16 12:22:50 +01:00
parent 68b8f44957
commit 7bfbb64899
12 changed files with 180 additions and 36 deletions

View file

@ -327,11 +327,6 @@ interface EventDriverSockets {
/// ditto /// ditto
bool setOption(StreamSocketFD socket, StreamSocketOption option, bool enable); bool setOption(StreamSocketFD socket, StreamSocketOption option, bool enable);
/// Low-level user data access. Use `getUserData` instead.
protected void* rawUserData(StreamSocketFD descriptor, size_t size, DataInitializer initialize, DataInitializer destroy) @system;
/// ditto
protected void* rawUserData(DatagramSocketFD descriptor, size_t size, DataInitializer initialize, DataInitializer destroy) @system;
/** Retrieves a reference to a user-defined value associated with a descriptor. /** Retrieves a reference to a user-defined value associated with a descriptor.
*/ */
@property final ref T userData(T, FD)(FD descriptor) @property final ref T userData(T, FD)(FD descriptor)
@ -341,6 +336,13 @@ interface EventDriverSockets {
static void destr(void* ptr) { destroy(*cast(T*)ptr); } static void destr(void* ptr) { destroy(*cast(T*)ptr); }
return *cast(T*)rawUserData(descriptor, T.sizeof, &init, &destr); return *cast(T*)rawUserData(descriptor, T.sizeof, &init, &destr);
} }
/// Low-level user data access. Use `getUserData` instead.
protected void* rawUserData(StreamSocketFD descriptor, size_t size, DataInitializer initialize, DataInitializer destroy) @system;
/// ditto
protected void* rawUserData(StreamListenSocketFD descriptor, size_t size, DataInitializer initialize, DataInitializer destroy) @system;
/// ditto
protected void* rawUserData(DatagramSocketFD descriptor, size_t size, DataInitializer initialize, DataInitializer destroy) @system;
} }
@ -384,8 +386,22 @@ interface EventDriverFiles {
Returns `false` $(I iff) the last reference was removed by this call. Returns `false` $(I iff) the last reference was removed by this call.
*/ */
bool releaseRef(FileFD descriptor); bool releaseRef(FileFD descriptor);
/** Retrieves a reference to a user-defined value associated with a descriptor.
*/
@property final ref T userData(T)(FileFD descriptor)
@trusted {
import std.conv : emplace;
static void init(void* ptr) { emplace(cast(T*)ptr); }
static void destr(void* ptr) { destroy(*cast(T*)ptr); }
return *cast(T*)rawUserData(descriptor, T.sizeof, &init, &destr);
} }
/// Low-level user data access. Use `userData` instead.
protected void* rawUserData(FileFD descriptor, size_t size, DataInitializer initialize, DataInitializer destroy) @system;
}
/** Cross-thread notifications /** Cross-thread notifications
"Events" can be used to wake up the event loop of a foreign thread. This is "Events" can be used to wake up the event loop of a foreign thread. This is
@ -428,6 +444,19 @@ interface EventDriverEvents {
Returns `false` $(I iff) the last reference was removed by this call. Returns `false` $(I iff) the last reference was removed by this call.
*/ */
bool releaseRef(EventID descriptor); bool releaseRef(EventID descriptor);
/** Retrieves a reference to a user-defined value associated with a descriptor.
*/
@property final ref T userData(T)(EventID descriptor)
@trusted {
import std.conv : emplace;
static void init(void* ptr) { emplace(cast(T*)ptr); }
static void destr(void* ptr) { destroy(*cast(T*)ptr); }
return *cast(T*)rawUserData(descriptor, T.sizeof, &init, &destr);
}
/// Low-level user data access. Use `userData` instead.
protected void* rawUserData(EventID descriptor, size_t size, DataInitializer initialize, DataInitializer destroy) @system;
} }
@ -496,6 +525,19 @@ interface EventDriverTimers {
/// Determines if the given timer's reference count equals one. /// Determines if the given timer's reference count equals one.
bool isUnique(TimerID descriptor) const; bool isUnique(TimerID descriptor) const;
/** Retrieves a reference to a user-defined value associated with a descriptor.
*/
@property final ref T userData(T)(TimerID descriptor)
@trusted {
import std.conv : emplace;
static void init(void* ptr) { emplace(cast(T*)ptr); }
static void destr(void* ptr) { destroy(*cast(T*)ptr); }
return *cast(T*)rawUserData(descriptor, T.sizeof, &init, &destr);
}
/// Low-level user data access. Use `userData` instead.
protected void* rawUserData(TimerID descriptor, size_t size, DataInitializer initialize, DataInitializer destroy) @system;
} }
interface EventDriverWatchers { interface EventDriverWatchers {
@ -516,6 +558,19 @@ interface EventDriverWatchers {
Returns `false` $(I iff) the last reference was removed by this call. Returns `false` $(I iff) the last reference was removed by this call.
*/ */
bool releaseRef(WatcherID descriptor); bool releaseRef(WatcherID descriptor);
/** Retrieves a reference to a user-defined value associated with a descriptor.
*/
@property final ref T userData(T)(WatcherID descriptor)
@trusted {
import std.conv : emplace;
static void init(void* ptr) { emplace(cast(T*)ptr); }
static void destr(void* ptr) { destroy(*cast(T*)ptr); }
return *cast(T*)rawUserData(descriptor, T.sizeof, &init, &destr);
}
/// Low-level user data access. Use `userData` instead.
protected void* rawUserData(WatcherID descriptor, size_t size, DataInitializer initialize, DataInitializer destroy) @system;
} }

View file

@ -192,18 +192,9 @@ final class PosixEventDriverCore(Loop : PosixEventLoop, Timers : EventDriverTime
return rawUserDataImpl(descriptor, size, initialize, destroy); return rawUserDataImpl(descriptor, size, initialize, destroy);
} }
private void* rawUserDataImpl(FD descriptor, size_t size, DataInitializer initialize, DataInitializer destroy) protected final void* rawUserDataImpl(FD descriptor, size_t size, DataInitializer initialize, DataInitializer destroy)
@system { @system {
FDSlot* fds = &m_loop.m_fds[descriptor].common; return m_loop.rawUserDataImpl(descriptor, size, initialize, destroy);
assert(fds.userDataDestructor is null || fds.userDataDestructor is destroy,
"Requesting user data with differing type (destructor).");
assert(size <= FDSlot.userData.length, "Requested user data is too large.");
if (size > FDSlot.userData.length) assert(false);
if (!fds.userDataDestructor) {
initialize(fds.userData.ptr);
fds.userDataDestructor = destroy;
}
return m_loop.m_fds[descriptor].common.userData.ptr;
} }
} }
@ -281,6 +272,20 @@ package class PosixEventLoop {
m_waiterCount--; m_waiterCount--;
*slot = m_fds.FullField.init; *slot = m_fds.FullField.init;
} }
package final void* rawUserDataImpl(size_t descriptor, size_t size, DataInitializer initialize, DataInitializer destroy)
@system {
FDSlot* fds = &m_fds[descriptor].common;
assert(fds.userDataDestructor is null || fds.userDataDestructor is destroy,
"Requesting user data with differing type (destructor).");
assert(size <= FDSlot.userData.length, "Requested user data is too large.");
if (size > FDSlot.userData.length) assert(false);
if (!fds.userDataDestructor) {
initialize(fds.userData.ptr);
fds.userDataDestructor = destroy;
}
return fds.userData.ptr;
}
} }

View file

@ -227,6 +227,11 @@ final class PosixEventDriverEvents(Loop : PosixEventLoop, Sockets : EventDriverS
return true; return true;
} }
final protected override void* rawUserData(EventID descriptor, size_t size, DataInitializer initialize, DataInitializer destroy)
@system {
return m_loop.rawUserDataImpl(descriptor, size, initialize, destroy);
}
private EventSlot* getSlot(EventID id) private EventSlot* getSlot(EventID id)
{ {
nogc_assert(id < m_loop.m_fds.length, "Invalid event ID."); nogc_assert(id < m_loop.m_fds.length, "Invalid event ID.");

View file

@ -799,8 +799,9 @@ final class PosixEventDriverSockets(Loop : PosixEventLoop) : EventDriverSockets
final override void addRef(SocketFD fd) final override void addRef(SocketFD fd)
{ {
assert(m_loop.m_fds[fd].common.refCount > 0, "Adding reference to unreferenced socket FD."); auto slot = () @trusted { return &m_loop.m_fds[fd]; } ();
m_loop.m_fds[fd].common.refCount++; assert(slot.common.refCount > 0, "Adding reference to unreferenced socket FD.");
slot.common.refCount++;
} }
final override bool releaseRef(SocketFD fd) final override bool releaseRef(SocketFD fd)
@ -843,26 +844,17 @@ final class PosixEventDriverSockets(Loop : PosixEventLoop) : EventDriverSockets
final protected override void* rawUserData(StreamSocketFD descriptor, size_t size, DataInitializer initialize, DataInitializer destroy) final protected override void* rawUserData(StreamSocketFD descriptor, size_t size, DataInitializer initialize, DataInitializer destroy)
@system { @system {
return rawUserDataImpl(descriptor, size, initialize, destroy); return m_loop.rawUserDataImpl(descriptor, size, initialize, destroy);
}
final protected override void* rawUserData(StreamListenSocketFD descriptor, size_t size, DataInitializer initialize, DataInitializer destroy)
@system {
return m_loop.rawUserDataImpl(descriptor, size, initialize, destroy);
} }
final protected override void* rawUserData(DatagramSocketFD descriptor, size_t size, DataInitializer initialize, DataInitializer destroy) final protected override void* rawUserData(DatagramSocketFD descriptor, size_t size, DataInitializer initialize, DataInitializer destroy)
@system { @system {
return rawUserDataImpl(descriptor, size, initialize, destroy); return m_loop.rawUserDataImpl(descriptor, size, initialize, destroy);
}
private void* rawUserDataImpl(FD descriptor, size_t size, DataInitializer initialize, DataInitializer destroy)
@system {
auto fds = &m_loop.m_fds[descriptor].common;
assert(fds.userDataDestructor is null || fds.userDataDestructor is destroy,
"Requesting user data with differing type (destructor).");
assert(size <= fds.userData.length, "Requested user data is too large.");
if (size > fds.userData.length) assert(false);
if (!fds.userDataDestructor) {
initialize(fds.userData.ptr);
fds.userDataDestructor = destroy;
}
return m_loop.m_fds[descriptor].common.userData.ptr;
} }
private sock_t createSocket(AddressFamily family, int type) private sock_t createSocket(AddressFamily family, int type)

View file

@ -77,6 +77,11 @@ final class InotifyEventDriverWatchers(Events : EventDriverEvents) : EventDriver
return true; return true;
} }
final protected override void* rawUserData(WatcherID descriptor, size_t size, DataInitializer initialize, DataInitializer destroy)
@system {
return m_loop.rawUserDataImpl(descriptor, size, initialize, destroy);
}
private void onChanges(FD fd) private void onChanges(FD fd)
{ {
processEvents(cast(WatcherID)fd); processEvents(cast(WatcherID)fd);
@ -211,6 +216,12 @@ final class FSEventsEventDriverWatchers(Events : EventDriverEvents) : EventDrive
FSEventStreamRelease*/ FSEventStreamRelease*/
assert(false, "TODO!"); assert(false, "TODO!");
} }
final protected override void* rawUserData(WatcherID descriptor, size_t size, DataInitializer initialize, DataInitializer destroy)
@system {
return m_loop.rawUserDataImpl(descriptor, size, initialize, destroy);
}
} }
@ -294,6 +305,11 @@ final class PollEventDriverWatchers(Events : EventDriverEvents) : EventDriverWat
return true; return true;
} }
final protected override void* rawUserData(WatcherID descriptor, size_t size, DataInitializer initialize, DataInitializer destroy)
@system {
return m_events.loop.rawUserDataImpl(cast(EventID)descriptor, size, initialize, destroy);
}
private void onEvent(EventID evt) private void onEvent(EventID evt)
{ {
import std.algorithm.mutation : swap; import std.algorithm.mutation : swap;

View file

@ -101,11 +101,14 @@ final class ThreadedFileEventDriver(Events : EventDriverEvents) : EventDriverFil
static struct FileInfo { static struct FileInfo {
IOInfo read; IOInfo read;
IOInfo write; IOInfo write;
int refCount; int refCount;
DataInitializer userDataDestructor;
ubyte[16*size_t.sizeof] userData;
} }
TaskPool m_fileThreadPool; TaskPool m_fileThreadPool;
ChoppedVector!FileInfo m_files; ChoppedVector!FileInfo m_files; // TODO: use the one from the posix loop
SmallIntegerSet!FileFD m_activeReads; SmallIntegerSet!FileFD m_activeReads;
SmallIntegerSet!FileFD m_activeWrites; SmallIntegerSet!FileFD m_activeWrites;
EventID m_readyEvent = EventID.invalid; EventID m_readyEvent = EventID.invalid;
@ -268,6 +271,20 @@ final class ThreadedFileEventDriver(Events : EventDriverEvents) : EventDriverFil
return true; return true;
} }
protected final override void* rawUserData(FileFD descriptor, size_t size, DataInitializer initialize, DataInitializer destroy)
@system {
FileInfo* fds = &m_files[descriptor];
assert(fds.userDataDestructor is null || fds.userDataDestructor is destroy,
"Requesting user data with differing type (destructor).");
assert(size <= FileInfo.userData.length, "Requested user data is too large.");
if (size > FileInfo.userData.length) assert(false);
if (!fds.userDataDestructor) {
initialize(fds.userData.ptr);
fds.userDataDestructor = destroy;
}
return fds.userData.ptr;
}
/// private /// private
static void taskFun(string op, UB)(ThreadedFileEventDriver fd, FileFD file, ulong offset, UB[] buffer) static void taskFun(string op, UB)(ThreadedFileEventDriver fd, FileFD file, ulong offset, UB[] buffer)
{ {

View file

@ -170,6 +170,20 @@ final class LoopTimeoutTimerDriver : EventDriverTimers {
return m_timers[descriptor].refCount == 1; return m_timers[descriptor].refCount == 1;
} }
protected final override void* rawUserData(TimerID descriptor, size_t size, DataInitializer initialize, DataInitializer destroy)
@system {
TimerSlot* fds = m_timers[descriptor];
assert(fds.userDataDestructor is null || fds.userDataDestructor is destroy,
"Requesting user data with differing type (destructor).");
assert(size <= TimerSlot.userData.length, "Requested user data is too large.");
if (size > TimerSlot.userData.length) assert(false);
if (!fds.userDataDestructor) {
initialize(fds.userData.ptr);
fds.userDataDestructor = destroy;
}
return fds.userData.ptr;
}
private void enqueueTimer(TimerSlot* tm) private void enqueueTimer(TimerSlot* tm)
nothrow { nothrow {
TimerSlot* ns; TimerSlot* ns;
@ -192,4 +206,7 @@ struct TimerSlot {
long timeout; // stdtime long timeout; // stdtime
long repeatDuration; long repeatDuration;
TimerCallback callback; // TODO: use a list with small-value optimization TimerCallback callback; // TODO: use a list with small-value optimization
DataInitializer userDataDestructor;
ubyte[16*size_t.sizeof] userData;
} }

View file

@ -98,6 +98,20 @@ final class WinAPIEventDriverCore : EventDriverCore {
m_exit = false; m_exit = false;
} }
package void* rawUserDataImpl(HANDLE handle, size_t size, DataInitializer initialize, DataInitializer destroy)
@system {
HandleSlot* fds = &m_handles[handle];
assert(fds.userDataDestructor is null || fds.userDataDestructor is destroy,
"Requesting user data with differing type (destructor).");
assert(size <= HandleSlot.userData.length, "Requested user data is too large.");
if (size > HandleSlot.userData.length) assert(false);
if (!fds.userDataDestructor) {
initialize(fds.userData.ptr);
fds.userDataDestructor = destroy;
}
return fds.userData.ptr;
}
protected override void* rawUserData(StreamSocketFD descriptor, size_t size, DataInitializer initialize, DataInitializer destroy) @system protected override void* rawUserData(StreamSocketFD descriptor, size_t size, DataInitializer initialize, DataInitializer destroy) @system
{ {
assert(false, "TODO!"); assert(false, "TODO!");
@ -208,6 +222,9 @@ private struct HandleSlot {
int refCount; int refCount;
TaggedAlgebraic!SpecificTypes specific; TaggedAlgebraic!SpecificTypes specific;
DataInitializer userDataDestructor;
ubyte[16*size_t.sizeof] userData;
@safe nothrow: @safe nothrow:
@property ref FileSlot file() { return specific.get!FileSlot; } @property ref FileSlot file() { return specific.get!FileSlot; }

View file

@ -126,6 +126,11 @@ final class WinAPIEventDriverEvents : EventDriverEvents {
return true; return true;
} }
protected override void* rawUserData(EventID descriptor, size_t size, DataInitializer initialize, DataInitializer destroy)
@system {
return m_core.rawUserDataImpl(idToHandle(descriptor), size, initialize, destroy);
}
private void triggerPending() private void triggerPending()
{ {
while (true) { while (true) {

View file

@ -154,6 +154,11 @@ final class WinAPIEventDriverFiles : EventDriverFiles {
}); });
} }
protected override void* rawUserData(FileFD descriptor, size_t size, DataInitializer initialize, DataInitializer destroy)
@system {
return m_core.rawUserDataImpl(idToHandle(descriptor), size, initialize, destroy);
}
private static void startIO(alias fun, bool RO)(HANDLE h, FileSlot.Direction!RO* slot) private static void startIO(alias fun, bool RO)(HANDLE h, FileSlot.Direction!RO* slot)
{ {
import std.algorithm.comparison : min; import std.algorithm.comparison : min;

View file

@ -754,6 +754,11 @@ final class WinAPIEventDriverSockets : EventDriverSockets {
return rawUserDataImpl(descriptor, size, initialize, destroy); return rawUserDataImpl(descriptor, size, initialize, destroy);
} }
final protected override void* rawUserData(StreamListenSocketFD descriptor, size_t size, DataInitializer initialize, DataInitializer destroy)
@system {
return rawUserDataImpl(descriptor, size, initialize, destroy);
}
final protected override void* rawUserData(DatagramSocketFD descriptor, size_t size, DataInitializer initialize, DataInitializer destroy) final protected override void* rawUserData(DatagramSocketFD descriptor, size_t size, DataInitializer initialize, DataInitializer destroy)
@system { @system {
return rawUserDataImpl(descriptor, size, initialize, destroy); return rawUserDataImpl(descriptor, size, initialize, destroy);
@ -770,7 +775,7 @@ final class WinAPIEventDriverSockets : EventDriverSockets {
initialize(fds.userData.ptr); initialize(fds.userData.ptr);
fds.userDataDestructor = destroy; fds.userDataDestructor = destroy;
} }
return m_sockets[descriptor].common.userData.ptr; return fds.userData.ptr;
} }
private void initSocketSlot(SocketFD fd) private void initSocketSlot(SocketFD fd)

View file

@ -69,6 +69,11 @@ final class WinAPIEventDriverWatchers : EventDriverWatchers {
return doReleaseRef(idToHandle(descriptor)); return doReleaseRef(idToHandle(descriptor));
} }
protected override void* rawUserData(WatcherID descriptor, size_t size, DataInitializer initialize, DataInitializer destroy)
@system {
return m_core.rawUserDataImpl(idToHandle(descriptor), size, initialize, destroy);
}
private static bool doReleaseRef(HANDLE handle) private static bool doReleaseRef(HANDLE handle)
{ {
auto core = WinAPIEventDriver.threadInstance.core; auto core = WinAPIEventDriver.threadInstance.core;